From dbb088b034e19e99ec209cbbc4eed3bff64172da Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Jul 2003 23:40:59 +0400 Subject: First version of new authentification procedure: now authentification is one-stage (instead of two-stage in 4.1) For now following tasks have been done: - PASSWORD() function was rewritten. PASSWORD() now returns SHA1 hash_stage2; for new passwords user.password contains '*'hash_stage2; sql_yacc.yy also fixed; - password.c: new functions were implemented, old rolled back to 4.0 state - server code was rewritten to use new authorization algorithm (check_user(), change user, and other stuff in sql/sql_parse.cc) - client code was rewritten to use new authorization algorithm (mysql_real_connect, myslq_authenticate in sql-common/client.c) - now server barks on 45-byte-length 4.1.0 passwords and refuses 4.1.0-style authentification. Users with 4.1.0 passwords are blocked (sql/sql_acl.cc) - mysqladmin.c was fixed to work correctly with new passwords Tests for 4.0-4.1.1, 4.1.1-4.1.1 (with or without db/password) logons was performed; mysqladmin also was tested. Additional check are nevertheless necessary. BitKeeper/etc/ignore: Added start_mysqld.sh mysys/main.cc to the ignore list client/mysqladmin.c: fixed with new password api include/mysql.h: So as scramble_323 accepts only null-terminated message, two scramble buffs are necessary. gotta be fixed include/mysql_com.h: new constants and password.c api changes libmysql/libmysql.c: mysql_change_user rewritten to work with new password api scripts/mysql_create_system_tables.sh: fixed 'Password' column length to 41 scripts/mysql_fix_privilege_tables.sql: fixed 'Password' column length to 41 sql-common/client.c: mysql_real_connect rewritten to support new handshake procedure sql/item_strfunc.cc: Item_func_password and Item_func_old_password rewritten with new password api sql/item_strfunc.h: bit commented, numbers replaced with #defined constants sql/mysql_priv.h: removed unnecessary declaration as now all constants defined is in mysql_com.h sql/mysqld.cc: scramble initialization moved to sql_parce.cc:check_connection sql/password.c: All 4.1 functions were rolled back to 4.0 with attempt to save all possible 4.0-4.1 changes. Names for 4.0 functions were suffixed with '_323' Functions for new handshake were added. sql/slave.cc: Fixed to new constant; Bug #766 remains to be fixed sql/slave.h: fixed to new constant; Buf #766 remains to be fixed sql/sql_acl.cc: rewritten to support new passwords (41 byte-long) and password api sql/sql_acl.h: ditto sql/sql_class.cc: initialization for new members added sql/sql_class.h: same thing as in struct mysql - scramble is used for new family of functions, scramble_323 - for old sql/sql_parse.cc: check_connections was renamed to check_connection as this name reflects better what this function does authorization part of check_connection was rewritten check_user was rewritten with new password and acl api new function 'authenticate', which optionally re-request scramble from client was added fixed some typos COM_CHANGE_USER piece of dipsatch_command() was rewritten sql/sql_repl.h: HASH_PASSWORD_LENGTH replaced with SCRAMBLED_PASSWORD_CHAR_LENGTH bug #766 remains sql/sql_yacc.yy: Two-argument form of PASSWORD() was removed PASSWORD() function was fixed with new password api. BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- .bzrignore | 2 + BitKeeper/etc/logging_ok | 1 + client/mysqladmin.c | 9 +- include/mysql.h | 4 +- include/mysql_com.h | 61 ++- libmysql/libmysql.c | 58 ++- scripts/mysql_create_system_tables.sh | 2 +- scripts/mysql_fix_privilege_tables.sql | 2 +- sql-common/client.c | 166 +++---- sql/item_strfunc.cc | 86 +--- sql/item_strfunc.h | 30 +- sql/mysql_priv.h | 3 - sql/mysqld.cc | 6 - sql/password.c | 828 +++++++++++++-------------------- sql/slave.cc | 6 +- sql/slave.h | 2 +- sql/sql_acl.cc | 667 +++++++++++++------------- sql/sql_acl.h | 13 +- sql/sql_class.cc | 1 + sql/sql_class.h | 14 +- sql/sql_parse.cc | 582 ++++++++++------------- sql/sql_repl.h | 2 +- sql/sql_yacc.yy | 50 +- 23 files changed, 1138 insertions(+), 1457 deletions(-) diff --git a/.bzrignore b/.bzrignore index 4e9ce4e41ab..a23384d4170 100644 --- a/.bzrignore +++ b/.bzrignore @@ -622,3 +622,5 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +start_mysqld.sh +mysys/main.cc diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 794edcdd968..ac862cc9770 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -51,6 +51,7 @@ jcole@sarvik.tfr.cafe.ee jcole@tetra.spaceapes.com jorge@linux.jorge.mysql.com kaj@work.mysql.com +kostja@oak.local lenz@kallisto.mysql.com lenz@mysql.com miguel@hegel.(none) diff --git a/client/mysqladmin.c b/client/mysqladmin.c index 018bcbc1963..f263d321a7b 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.c @@ -769,9 +769,12 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return 1; } if (argv[1][0]) - make_scrambled_password(crypted_pw,argv[1], - (find_type(argv[0], &command_typelib, 2) == - ADMIN_OLD_PASSWORD), &rand_st); + { + if (find_type(argv[0], &command_typelib, 2) == ADMIN_OLD_PASSWORD) + make_scrambled_password_323(crypted_pw, argv[1]); + else + make_scrambled_password(crypted_pw, argv[1]); + } else crypted_pw[0]=0; /* No password */ sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw); diff --git a/include/mysql.h b/include/mysql.h index bd63a10ba45..91ef481e7f7 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -227,7 +227,9 @@ typedef struct st_mysql enum mysql_status status; my_bool free_me; /* If free in mysql_close */ my_bool reconnect; /* set to 1 if automatic reconnect */ - char scramble_buff[21]; /* New protocol requires longer scramble*/ + + char scramble[SCRAMBLE_LENGTH+1]; /* for new servers */ + char scramble_323[SCRAMBLE_LENGTH_323+1]; /* for old servers */ /* Set if this is the original connection, not a master or a slave we have diff --git a/include/mysql_com.h b/include/mysql_com.h index e87001ff27d..c1f18160667 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -48,8 +48,15 @@ enum enum_server_command }; -#define SCRAMBLE_LENGTH 8 -#define SCRAMBLE41_LENGTH 20 +/* + Length of random string sent by server on handshake; this is also length of + obfuscated password, recieved from client +*/ +#define SCRAMBLE_LENGTH 20 +#define SCRAMBLE_LENGTH_323 8 +/* length of password stored in the db: new passwords are preceeded with '*' */ +#define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1) +#define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2) #define NOT_NULL_FLAG 1 /* Field can't be NULL */ @@ -300,31 +307,35 @@ extern "C" { extern unsigned long max_allowed_packet; extern unsigned long net_buffer_length; -void randominit(struct rand_struct *,unsigned long seed1, - unsigned long seed2); +/* + These functions are used for authentication by client and server and + implemented in sql/password.c +*/ + +void randominit(struct rand_struct *, unsigned long seed1, + unsigned long seed2); double my_rnd(struct rand_struct *); -void make_scrambled_password(char *to,const char *password, - my_bool force_old_scramble,struct rand_struct *rand_st); -int get_password_length(my_bool force_old_scramble); -char get_password_version(const char* password); -void create_random_string(int length,struct rand_struct *rand_st,char* target); -my_bool validate_password(const char* password, const char* message, - unsigned long* salt); -void password_hash_stage1(char *to, const char *password); -void password_hash_stage2(char *to,const char *salt); -void password_crypt(const char* from,char* to, const char* password,int length); -void get_hash_and_password(unsigned long* salt, unsigned char pversion,char* hash, - unsigned char* bin_password); -void get_salt_from_password(unsigned long *res,const char *password); -void create_key_from_old_password(const char* password,char* key); -void make_password_from_salt(char *to, unsigned long *hash_res, - unsigned char password_version); -char *scramble(char *to,const char *message,const char *password, - my_bool old_ver); -my_bool check_scramble(const char *, const char *message, - unsigned long *salt,my_bool old_ver); +void create_random_string(char *to, uint length, struct rand_struct *rand_st); + +void hash_password(ulong *to, const char *password); +void make_scrambled_password_323(char *to, const char *password); +char *scramble_323(char *to, const char *message, const char *password, + my_bool old_ver); +my_bool check_scramble_323(const char *, const char *message, + unsigned long *salt, my_bool old_ver); +void get_salt_from_password_323(unsigned long *res, const char *password); +void make_password_from_salt_323(char *to, const unsigned long *salt); + +void make_scrambled_password(char *to, const char *password); +char *scramble(char *to, const char *message, const char *password); +my_bool check_scramble(const char *reply, const char *message, + const unsigned char *hash_stage2); +void get_salt_from_password(unsigned char *res, const char *password); +void make_password_from_salt(char *to, const unsigned char *hash_stage2); + +/* end of password.c */ + char *get_tty_password(char *opt_message); -void hash_password(unsigned long *result, const char *password); const char *mysql_errno_to_sqlstate(unsigned int mysql_errno); /* Some other useful functions */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 771278c1dbb..6bc38abb060 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -616,41 +616,51 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, /* Store user into the buffer */ end=strmov(end,user)+1; - /* - We always start with old type handshake the only difference is message sent - If server handles secure connection type we'll not send the real scramble - */ - if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + /* write scrambled password according to server capabilities */ + if (passwd[0]) { - if (passwd[0]) - { - /* Prepare false scramble */ - bfill(end, SCRAMBLE_LENGTH, 'x'); - end+=SCRAMBLE_LENGTH; - *end=0; - - } - else /* For empty password */ - *end=0; /* zero length scramble */ + /* Write NULL-terminated scrambled password: */ + end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? + scramble(end, mysql->scramble, passwd) : + scramble_323(end, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)); } else - { - /* - Real scramble is only sent to old servers. This can be blocked - by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); - */ - end=scramble(end, mysql->scramble_buff, passwd, - (my_bool) (mysql->protocol_version == 9)); - } + *end= '\0'; // empty password /* Add database if needed */ end=strmov(end+1,db ? db : ""); /* Write authentication package */ simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); - if (mysql_autenticate(mysql, passwd)) + NET *net= &mysql->net; + ulong pkt_length= net_safe_read(mysql); + + if (pkt_length == packet_error) goto error; + if (net->read_pos[0] == mysql->scramble_323[0] && + pkt_length == SCRAMBLE_LENGTH_323 + 1 && + mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + { + /* + By sending this very specific reply server asks us to send scrambled + password in old format. The reply contains scramble_323. + */ + scramble_323(buff, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)); + if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) + { + net->last_errno= CR_SERVER_LOST; + strmov(net->sqlstate, unknown_sqlstate); + strmov(net->last_error,ER(net->last_errno)); + goto error; + } + /* Read what server thinks about out new auth message report */ + if (net_safe_read(mysql) == packet_error) + goto error; + } + /* Free old connect information */ my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 2739c45e750..c4cdc7b52d7 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -108,7 +108,7 @@ then c_u="$c_u CREATE TABLE user (" c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL," c_u="$c_u User char(16) binary DEFAULT '' NOT NULL," - c_u="$c_u Password char(45) binary DEFAULT '' NOT NULL," + c_u="$c_u Password char(41) binary DEFAULT '' NOT NULL," c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL," c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL," diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 43dc6d89481..8c5b29a49ff 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -4,7 +4,7 @@ ALTER TABLE host type=MyISAM; ALTER TABLE func type=MyISAM; ALTER TABLE columns_priv type=MyISAM; ALTER TABLE tables_priv type=MyISAM; -ALTER TABLE user change Password Password char(45) not null; +ALTER TABLE user change Password Password char(41) not null; ALTER TABLE user add File_priv enum('N','Y') NOT NULL; CREATE TABLE IF NOT EXISTS func ( name char(64) DEFAULT '' NOT NULL, diff --git a/sql-common/client.c b/sql-common/client.c index 721164c8301..35dea62edc3 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1334,76 +1334,6 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused))) #endif /* HAVE_OPENSSL */ -/* - Handle password authentication -*/ - -my_bool mysql_autenticate(MYSQL *mysql, const char *passwd) -{ - ulong pkt_length; - NET *net= &mysql->net; - char buff[SCRAMBLE41_LENGTH]; - char password_hash[SCRAMBLE41_LENGTH]; /* Used for storage of stage1 hash */ - - /* We shall only query server if it expect us to do so */ - if ((pkt_length=net_safe_read(mysql)) == packet_error) - goto error; - - if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) - { - /* - This should always happen with new server unless empty password - OK/Error packets have zero as the first char - */ - if (pkt_length == 24 && net->read_pos[0]) - { - /* Old passwords will have '*' at the first byte of hash */ - if (net->read_pos[0] != '*') - { - /* Build full password hash as it is required to decode scramble */ - password_hash_stage1(buff, passwd); - /* Store copy as we'll need it later */ - memcpy(password_hash,buff,SCRAMBLE41_LENGTH); - /* Finally hash complete password using hash we got from server */ - password_hash_stage2(password_hash,(const char*) net->read_pos); - /* Decypt and store scramble 4 = hash for stage2 */ - password_crypt((const char*) net->read_pos+4,mysql->scramble_buff, - password_hash, SCRAMBLE41_LENGTH); - mysql->scramble_buff[SCRAMBLE41_LENGTH]=0; - /* Encode scramble with password. Recycle buffer */ - password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH); - } - else - { - /* Create password to decode scramble */ - create_key_from_old_password(passwd,password_hash); - /* Decypt and store scramble 4 = hash for stage2 */ - password_crypt((const char*) net->read_pos+4,mysql->scramble_buff, - password_hash, SCRAMBLE41_LENGTH); - mysql->scramble_buff[SCRAMBLE41_LENGTH]=0; - /* Finally scramble decoded scramble with password */ - scramble(buff, mysql->scramble_buff, passwd,0); - } - /* Write second package of authentication */ - if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net)) - { - net->last_errno= CR_SERVER_LOST; - strmov(net->sqlstate, unknown_sqlstate); - strmov(net->last_error,ER(net->last_errno)); - goto error; - } - /* Read what server thinks about out new auth message report */ - if (net_safe_read(mysql) == packet_error) - goto error; - } - } - return 0; - -error: - return 1; -} - - /* Note that the mysql argument must be initialized with mysql_init() before calling mysql_real_connect ! @@ -1481,7 +1411,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->server_status=SERVER_STATUS_AUTOCOMMIT; /* - Grab a socket and connect it to the server + Part 0: Grab a socket and connect it to the server */ #if defined(HAVE_SMEM) if ((!mysql->options.protocol || @@ -1682,6 +1612,11 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, strmov(net->last_error,ER(net->last_errno)); goto error; } + + /* + Part 1: Connection established, read and parse first packet + */ + if ((pkt_length=net_safe_read(mysql)) == packet_error) goto error; @@ -1702,8 +1637,14 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, end=strend((char*) net->read_pos+1); mysql->thread_id=uint4korr(end+1); end+=5; - strmake(mysql->scramble_buff,end,8); - end+=9; + /* + Scramble is split into two parts because old clients does not understand + long scrambles; here goes the first part. + */ + strmake(mysql->scramble_323, end, SCRAMBLE_LENGTH_323); + end+= SCRAMBLE_LENGTH_323+1; + memcpy(mysql->scramble, mysql->scramble_323, SCRAMBLE_LENGTH_323); + if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) mysql->server_capabilities=uint2korr(end); if (pkt_length >= (uint) (end+18 - (char*) net->read_pos)) @@ -1712,6 +1653,13 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->server_language=end[2]; mysql->server_status=uint2korr(end+3); } + end+= 18; + if (pkt_length >= (uint) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 - + (char *) net->read_pos)) + strmake(mysql->scramble+SCRAMBLE_LENGTH_323, end, + SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323); + else + mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION; /* Set character set */ if ((charset_name=mysql->options.charset_name)) @@ -1783,9 +1731,12 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->unix_socket=0; strmov(mysql->server_version,(char*) net->read_pos+1); mysql->port=port; - client_flag|=mysql->options.client_flag; - /* Send client information for access check */ + /* + Part 2: format and send client info to the server for access check + */ + + client_flag|=mysql->options.client_flag; client_flag|=CLIENT_CAPABILITIES; if (client_flag & CLIENT_MULTI_QUERIES) client_flag|= CLIENT_MULTI_RESULTS; @@ -1881,35 +1832,18 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, #include "_cust_libmysql.h" #endif DBUG_PRINT("info",("user: %s",end)); - /* - We always start with old type handshake the only difference is message sent - If server handles secure connection type we'll not send the real scramble - */ - if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + end= strend(end) + 1; + if (passwd[0]) { - if (passwd[0]) - { - /* Prepare false scramble */ - end=strend(end)+1; - bfill(end, SCRAMBLE_LENGTH, 'x'); - end+=SCRAMBLE_LENGTH; - *end=0; - } - else /* For empty password*/ - { - end=strend(end)+1; - *end=0; /* Store zero length scramble */ - } + /* Write NULL-terminated scrambled password: */ + end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? + scramble(end, mysql->scramble, passwd) : + scramble_323(end, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)); } else - { - /* - Real scramble is only sent to old servers. This can be blocked - by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1); - */ - end=scramble(strend(end)+1, mysql->scramble_buff, passwd, - (my_bool) (mysql->protocol_version == 9)); - } + *end= '\0'; /* empty password */ + /* Add database if needed */ if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) { @@ -1925,10 +1859,38 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, strmov(net->last_error,ER(net->last_errno)); goto error; } + + /* + Part 3: Authorization data's been sent. Now server can reply with + OK-packet, or re-request scrambled password. + */ - if (mysql_autenticate(mysql, passwd)) + if ((pkt_length=net_safe_read(mysql)) == packet_error) goto error; + if (net->read_pos[0] == mysql->scramble_323[0] && + pkt_length == SCRAMBLE_LENGTH_323 + 1 && + mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + { + /* + By sending this very specific reply server asks us to send scrambled + password in old format. The reply contains scramble_323. + */ + scramble_323(buff, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)); + if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) + { + net->last_errno= CR_SERVER_LOST; + strmov(net->sqlstate, unknown_sqlstate); + strmov(net->last_error,ER(net->last_errno)); + goto error; + } + /* Read what server thinks about out new auth message report */ + if (net_safe_read(mysql) == packet_error) + goto error; + } + + if (client_flag & CLIENT_COMPRESS) /* We will use compression */ net->compress=1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ae63ac85d4d..f8488565b75 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1346,97 +1346,35 @@ void Item_func_trim::fix_length_and_dec() } - - -void Item_func_password::fix_length_and_dec() -{ - /* - If PASSWORD() was called with only one argument, it depends on a random - number so we need to save this random number into the binary log. - If called with two arguments, it is repeatable. - */ - if (arg_count == 1) - { - THD *thd= current_thd; - thd->rand_used= 1; - thd->rand_saved_seed1= thd->rand.seed1; - thd->rand_saved_seed2= thd->rand.seed2; - } - max_length= get_password_length(use_old_passwords); -} - -/* - Password() function has 2 arguments. Second argument can be used - to make results repeatable -*/ +/* Item_func_password */ String *Item_func_password::val_str(String *str) { - struct rand_struct rand_st; // local structure for 2 param version - ulong seed=0; // seed to initialise random generator to - - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; - - if (arg_count == 1) - { - if (res->length() == 0) - return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords, - ¤t_thd->rand); - str->set(tmp_value,get_password_length(use_old_passwords),res->charset()); - return str; - } - else - { - /* We'll need the buffer to get second parameter */ - char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); - String *key =args[1]->val_str(&tmp_key_value); - - /* Check second argument for NULL value. First one is already checked */ - if ((null_value=args[1]->null_value)) - return 0; - - /* This shall be done after checking for null for proper results */ - if (res->length() == 0) - return &empty_string; - - /* Generate the seed first this allows to avoid double allocation */ - char* seed_ptr=key->c_ptr(); - while (*seed_ptr) - { - seed=(seed*211+*seed_ptr) & 0xffffffffL; /* Use simple hashing */ - seed_ptr++; - } - - /* Use constants which allow nice random values even with small seed */ - randominit(&rand_st, - (ulong) ((ulonglong) seed*111111+33333333L) & (ulong) 0xffffffff, - (ulong) ((ulonglong) seed*1111+55555555L) & (ulong) 0xffffffff); - - make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords, - &rand_st); - str->set(tmp_value,get_password_length(use_old_passwords),res->charset()); - return str; - } + if (res->length() == 0) + return &empty_string; + make_scrambled_password(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset()); + return str; } +/* Item_func_old_password */ + String *Item_func_old_password::val_str(String *str) { - String *res =args[0]->val_str(str); + String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - make_scrambled_password(tmp_value,res->c_ptr(),1,¤t_thd->rand); - str->set(tmp_value,16,res->charset()); + make_scrambled_password_323(tmp_value, res->c_ptr()); + str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset()); return str; } - #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') String *Item_func_encrypt::val_str(String *str) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6cc6d730627..11f5a66b3d1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -254,30 +254,44 @@ public: }; +/* + Item_func_password -- new (4.1.1) PASSWORD() function implementation. + Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new + password format, sha1(sha1(password) is so-called hash_stage2 value. + Length of returned string is always 41 byte. To find out how entire + authentification procedure works, see comments in password.c. +*/ + class Item_func_password :public Item_str_func { - char tmp_value[64]; /* This should be enough for new password format */ + char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; public: Item_func_password(Item *a) :Item_str_func(a) {} - Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {} - String *val_str(String *); - void fix_length_and_dec(); + String *val_str(String *str); + void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } const char *func_name() const { return "password"; } }; +/* + Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0 + compatibility mode. This item is created in sql_yacc.yy when + 'use_old_passwords' session variable is set, and to handle OLD_PASSWORD() + function. +*/ + class Item_func_old_password :public Item_str_func { - char tmp_value[17]; /* old password length +1 */ + char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1]; public: Item_func_old_password(Item *a) :Item_str_func(a) {} - String *val_str(String *); - void fix_length_and_dec() { max_length = get_password_length(1); } + String *val_str(String *str); + void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } const char *func_name() const { return "old_password"; } + unsigned int size_of() { return sizeof(*this);} }; - class Item_func_des_encrypt :public Item_str_func { String tmp_value; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index aca84f1bcb3..13ff168e553 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -74,9 +74,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; ****************************************************************************/ #define ACL_CACHE_SIZE 256 -/* Password lengh for 4.1 version previous versions had 16 bytes password hash */ -#define HASH_PASSWORD_LENGTH 45 -#define HASH_OLD_PASSWORD_LENGTH 16 #define HOST_CACHE_SIZE 128 #define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_FIELDS_BEFORE_HASH 32 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 72ee3e30c63..2677973ff0e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2743,12 +2743,6 @@ static void create_new_thread(THD *thd) if (thread_count-delayed_insert_threads > max_used_connections) max_used_connections=thread_count-delayed_insert_threads; thd->thread_id=thread_id++; - for (uint i=0; i < 8 ; i++) // Generate password teststring - thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33); - thd->scramble[8]=0; - // Back it up as old clients may need it - memcpy(thd->old_scramble,thd->scramble,9); - thd->real_id=pthread_self(); // Keep purify happy diff --git a/sql/password.c b/sql/password.c index 257547671e5..be6514d89c6 100644 --- a/sql/password.c +++ b/sql/password.c @@ -29,28 +29,33 @@ The password is saved (in user.password) by using the PASSWORD() function in mysql. + This is .c file because it's used in libmysqlclient, which is entirely in C. + (we need it to be portable to a variety of systems). Example: update user set password=PASSWORD("hello") where user="test" This saves a hashed number as a string in the password field. + The new autentication is performed in following manner: - New in MySQL 4.1 authentication works even more secure way. - At the first step client sends user name to the sever, and password if - it is empty. So in case of empty password authentication is as fast as before. - At the second stap servers sends scramble to client, which is encoded with - password stage2 hash stored in the password database as well as salt, needed - for client to build stage2 password to decrypt scramble. - Client decrypts the scramble and encrypts it once again with stage1 password. - This information is sent to server. - Server decrypts the scramble to get stage1 password and hashes it to get - stage2 hash. This hash is when compared to hash stored in the database. + SERVER: public_seed=create_random_string() + send(public_seed) - This authentication needs 2 packet round trips instead of one but it is much - stronger. Now if one will steal mysql database content he will not be able - to break into MySQL. + CLIENT: recv(public_seed) + hash_stage1=sha1("password") + hash_stage2=sha1(hash_stage1) + reply=xor(hash_stage1, sha1(public_seed,hash_stage2) - New Password handling functions by Peter Zaitsev + // this three steps are done in scramble() + send(reply) + + + SERVER: recv(reply) + hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) + candidate_hash2=sha1(hash_stage1) + check(candidate_hash2==hash_stage2) + + // this three steps are done in check_scramble() *****************************************************************************/ @@ -60,31 +65,21 @@ #include #include "mysql.h" - - -/* Character to use as version identifier for version 4.1 */ -#define PVERSION41_CHAR '*' - -/* Scramble length for new password version */ - +/************ MySQL 3.23-4.0 authentification routines: untouched ***********/ /* New (MySQL 3.21+) random generation structure initialization - SYNOPSIS randominit() rand_st OUT Structure to initialize seed1 IN First initialization parameter seed2 IN Second initialization parameter - - RETURN - none */ -void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) -{ /* For mysql 3.21.# */ +void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) +{ /* For mysql 3.21.# */ #ifdef HAVE_purify - bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ + bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */ #endif rand_st->max_value= 0x3FFFFFFFL; rand_st->max_value_dbl=(double) rand_st->max_value; @@ -95,18 +90,15 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) /* Old (MySQL 3.20) random generation structure initialization - + XXX: is to be deleted very soon! SYNOPSIS old_randominit() rand_st OUT Structure to initialize seed1 IN First initialization parameter - - RETURN - none */ -static void old_randominit(struct rand_struct *rand_st,ulong seed1) -{ /* For mysql 3.20.# */ +static void old_randominit(struct rand_struct *rand_st, ulong seed1) +{ /* For mysql 3.20.# */ rand_st->max_value= 0x01FFFFFFL; rand_st->max_value_dbl=(double) rand_st->max_value; seed1%=rand_st->max_value; @@ -115,14 +107,12 @@ static void old_randominit(struct rand_struct *rand_st,ulong seed1) /* - Generate Random number - + Generate random number. SYNOPSIS my_rnd() rand_st INOUT Structure used for number generation - - RETURN - Generated pseudo random number + RETURN VALUE + generated pseudo random number */ double my_rnd(struct rand_struct *rand_st) @@ -134,63 +124,12 @@ double my_rnd(struct rand_struct *rand_st) /* - Generate String of printable random characters of requested length - String will not be zero terminated. - + Generate binary hash from raw text string + Used for Pre-4.1 password handling SYNOPSIS - create_random_string() - length IN Lenght of - rand_st INOUT Structure used for number generation - target OUT Buffer for generation - - RETURN - none -*/ - -void create_random_string(int length,struct rand_struct *rand_st,char *target) -{ - char *end=target+length; - /* Use pointer arithmetics as it is faster way to do so. */ - for (; target= '0' && X <= '9' ? X-'0' : + X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10); } /* - Convert password from binary string form to salt form - Used for MySQL 4.1 password handling - + Convert password from hex string (as stored in mysql.user) to binary form. SYNOPSIS - get_salt_from_bin_password() - res OUT Store salt form password here - password IN Binary password to be converted - salt IN hashing-salt to be used for salt form generation - - RETURN - none + get_salt_from_password_323() + res OUT store salt here + password IN password string as stored in mysql.user + NOTE + This function does not have length check for passwords. It will just crash + Password hashes in old format must have length divisible by 8 */ -void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt) +void get_salt_from_password_323(ulong *res, const char *password) { - unsigned char *password_end=password+SCRAMBLE41_LENGTH; - *res=salt; - res++; - - /* Process password of known length*/ - while (password0 + create_random_string() + to OUT buffer for generation; must be at least length+1 bytes + long; result string is always null-terminated + length IN how many random characters to put in buffer + rand_st INOUT structure used for number generation */ -int get_password_length(my_bool force_old_scramble) +void create_random_string(char *to, uint length, struct rand_struct *rand_st) { - return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1; + char *end= to + length; + /* Use pointer arithmetics as it is faster way to do so. */ + for (; to < end; to++) + *to= (char) (my_rnd(rand_st)*94+33); + *to= '\0'; } -/* - Get version of the password based on mysql.user password string - - SYNOPSIS - get_password_version() - password IN Password string as stored in mysql.user - - RETURN - 0 for pre 4.1 passwords - !0 password version char for newer passwords -*/ +/* Character to use as version identifier for version 4.1 */ -char get_password_version(const char *password) -{ - if (password==NULL) return 0; - if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR; - return 0; -} +#define PVERSION41_CHAR '*' /* - Get integer value of Hex character - + Convert given octet sequence to asciiz string of hex characters; + str..str+len and 'to' may not overlap. SYNOPSIS - char_val() - X IN Character to find value for - - RETURN - Appropriate integer value + octet2hex() + buf OUT output buffer. Must be at least 2*len+1 bytes + str, len IN the beginning and the length of the input string */ - - -static inline unsigned int char_val(char X) +static +void +octet2hex(char *to, const uint8 *str, uint len) { - return (uint) (X >= '0' && X <= '9' ? X-'0' : - X >= 'A' && X <= 'Z' ? X-'A'+10 : - X-'a'+10); + static const char alphabet[] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + const uint8 *str_end= str + len; + for (; str != str_end; ++str) + { + *to++= alphabet[(*str & 0xF0) >> 4]; + *to++= alphabet[*str & 0x0F]; + } + *to++= '\0'; } /* - Get Binary salt from password as in mysql.user format - + Convert given asciiz string of hex (0..9 a..f) characters to octet + sequence. SYNOPSIS - get_salt_from_password() - res OUT Store binary salt here - password IN Password string as stored in mysql.user - - RETURN - none - - NOTE - This function does not have length check for passwords. It will just crash - Password hashes in old format must have length divisible by 8 -*/ - -void get_salt_from_password(ulong *res,const char *password) + hex2octet() + to OUT buffer to place result; must be at least len/2 bytes + str, len IN begin, length for character string; str and to may not + overlap; len % 2 == 0 +*/ + +static +void +hex2octet(uint8 *to, const char *str, uint len) { - if (password) /* zero salt corresponds to empty password */ + const char *str_end= str + len; + while (str < str_end) { - if (password[0]==PVERSION41_CHAR) /* if new password */ - { - uint val=0; - uint i; - password++; /* skip version identifier */ - - /*get hashing salt from password and store in in the start of array */ - for (i=0 ; i < 4 ; i++) - val=(val << 4)+char_val(*password++); - *res++=val; - } - /* We process old passwords the same way as new ones in other case */ -#ifdef EXTRA_DEBUG - if (strlen(password)%8!=0) - fprintf(stderr,"Warning: Incorrect password length for salting: %d\n", - strlen(password)); -#endif - while (*password) - { - ulong val=0; - uint i; - for (i=0 ; i < 8 ; i++) - val=(val << 4)+char_val(*password++); - *res++=val; - } + *to= char_val(*str++) << 4; + *to++|= char_val(*str++); } - return; } /* - Get string version as stored in mysql.user from salt form - + Encrypt/Decrypt function used for password encryption in authentication. + Simple XOR is used here but it is OK as we crypt random strings. Note, + that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1) SYNOPSIS - make_password_from_salt() - to OUT Store resulting string password here - hash_res IN Password in salt format - password_version - IN According to which version salt should be treated - - RETURN - none + my_crypt() + to OUT buffer to hold crypted string; must be at least len bytes + long; to and s1 (or s2) may be the same. + s1, s2 IN input strings (of equal length) + len IN length of s1 and s2 */ -void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version) +static +void +my_crypt(char *to, const uint8 *s1, const uint8 *s2, uint len) { - if (!password_version) /* Handling of old passwords. */ - sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]); - else - if (password_version==PVERSION41_CHAR) - sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1], - hash_res[2],hash_res[3],hash_res[4],hash_res[5]); - else /* Just use empty password if we can't handle it. This should not happen */ - to[0]='\0'; + const uint8 *s1_end= s1 + len; + while (s1 < s1_end) + *to++= *s1++ ^ *s2++; } /* - Convert password in salted form to binary string password and hash-salt - For old password this involes one more hashing - + MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice + applied to the password string, and then produced octet sequence is + converted to hex string. + The result of this function is used as return value from PASSWORD() and + is stored in the database. SYNOPSIS - get_hash_and_password() - salt IN Salt to convert from - pversion IN Password version to use - hash OUT Store zero ended hash here - bin_password OUT Store binary password here (no zero at the end) - - RETURN - 0 for pre 4.1 passwords - !0 password version char for newer passwords + make_scrambled_password() + buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string + password IN NULL-terminated password string */ -void get_hash_and_password(ulong *salt, uint8 pversion, char *hash, - unsigned char *bin_password) +void +make_scrambled_password(char *to, const char *password) { - int t; - ulong* salt_end; - ulong val; - SHA1_CONTEXT context; - - if (pversion) /* New password version assumed */ - { - salt_end=salt+5; - sprintf(hash,"%04x",(unsigned short)salt[0]); - while (salt=0; t--) - { - bin_password[t]= (char) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ - } - bin_password+=4; /* Get to next 4 chars*/ - } - } - else - { - unsigned char *bp= bin_password; /* Binary password loop pointer */ - - /* Use zero starting hash as an indication of old password */ - hash[0]=0; - salt_end=salt+2; - /* Encode salt using SHA1 here */ - sha1_reset(&context); - while (salt=0;t--) - { - bp[t]= (uchar) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ - } - bp+= 4; /* Get to next 4 chars*/ - salt++; - } - /* Use 8 bytes of binary password for hash */ - sha1_input(&context,(uint8*)bin_password,8); - sha1_result(&context,(uint8*)bin_password); - } + SHA1_CONTEXT sha1_context; + uint8 hash_stage2[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* stage 1: hash password */ + sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_result(&sha1_context, (uint8 *) to); + /* stage 2: hash stage1 output */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE); + /* separate buffer is used to pass 'to' in octet2hex */ + sha1_result(&sha1_context, hash_stage2); + /* convert hash_stage2 to hex string */ + *to++= PVERSION41_CHAR; + octet2hex(to, hash_stage2, SHA1_HASH_SIZE); } - + /* - Create key from old password to decode scramble - Used in 4.1 authentication with passwords stored old way - + Produce an obscure octet sequence from password and random + string, recieved from the server. This sequence corresponds to the + password, but password can not be easily restored from it. The sequence + is then sent to the server for validation. Trailing zero is stored in + the buf. + This function is used by client to create authenticated reply to the + server's greeting. SYNOPSIS - create_key_from_old_password() - passwd IN Password used for key generation - key OUT Created 20 bytes key - - RETURN - None + scramble() + buf OUT store scrambled string here. The buf must be at least + SHA1_HASH_SIZE+1 bytes long. + message IN random message, must be exactly SCRAMBLE_LENGTH long and + NULL-terminated. + password IN users' password + RETURN VALUE + end of scrambled string */ - -void create_key_from_old_password(const char *passwd, char *key) +char * +scramble(char *to, const char *message, const char *password) { - char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */ - ulong salt[6]; /* Salt (large for safety) */ - /* At first hash password to the string stored in password */ - make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL); - /* Now convert it to the salt form */ - get_salt_from_password(salt,buffer); - /* Finally get hash and bin password from salt */ - get_hash_and_password(salt,0,buffer,(unsigned char*) key); + SHA1_CONTEXT sha1_context; + uint8 hash_stage1[SHA1_HASH_SIZE]; + uint8 hash_stage2[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* stage 1: hash password */ + sha1_input(&sha1_context, (uint8 *) password, strlen(password)); + sha1_result(&sha1_context, hash_stage1); + /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE); + sha1_result(&sha1_context, hash_stage2); + /* create crypt string as sha1(message, hash_stage2) */; + sha1_reset(&sha1_context); + sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + /* xor allows 'from' and 'to' overlap: lets take advantage of it */ + sha1_result(&sha1_context, (uint8 *) to); + my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH); + to[SHA1_HASH_SIZE]= '\0'; + return to + SHA1_HASH_SIZE; } /* - Scramble string with password - Used at pre 4.1 authentication phase. - + Check that scrambled message corresponds to the password; the function + is used by server to check that recieved reply is authentic. + This function does not check lengths of given strings: message must be + null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE + long (if not, something fishy is going on). SYNOPSIS - scramble() - to OUT Store scrambled message here - message IN Message to scramble - password IN Password to use while scrambling - old_ver IN Forse old version random number generator - - RETURN - End of scrambled string + check_scramble() + scramble IN clients' reply, presumably produced by scramble() + message IN original random string, previously sent to client + (presumably second argument of scramble()), must be + exactly SCRAMBLE_LENGTH long and NULL-terminated. + hash_stage2 IN hex2octet-decoded database entry + RETURN VALUE + 0 password is correct + !0 password is invalid */ -char *scramble(char *to,const char *message,const char *password, - my_bool old_ver) +my_bool +check_scramble(const char *scramble, const char *message, + const uint8 *hash_stage2) { - struct rand_struct rand_st; - ulong hash_pass[2],hash_message[2]; - char message_buffer[9]; /* Real message buffer */ - char *msg=message_buffer; - - /* We use special message buffer now as new server can provide longer hash */ - - memcpy(message_buffer,message,8); - message_buffer[8]=0; - - if (password && password[0]) - { - char *to_start=to; - hash_password(hash_pass,password); - hash_password(hash_message,message_buffer); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); - while (*msg++) - *to++= (char) (floor(my_rnd(&rand_st)*31)+64); - if (!old_ver) - { /* Make it harder to break */ - char extra=(char) (floor(my_rnd(&rand_st)*31)); - while (to_start != to) - *(to_start++)^=extra; - } - } - *to=0; - return to; + SHA1_CONTEXT sha1_context; + uint8 buf[SHA1_HASH_SIZE]; + uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; + + sha1_reset(&sha1_context); + /* create key to encrypt scramble */ + sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); + sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); + sha1_result(&sha1_context, buf); + /* encrypt scramble */ + my_crypt((char *) buf, buf, (const uint8 *) scramble, SCRAMBLE_LENGTH); + /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ + sha1_reset(&sha1_context); + sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); + sha1_result(&sha1_context, hash_stage2_reassured); + return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE); } /* - Check scrambled message - Used for pre 4.1 password handling - + Convert scrambled password from asciiz hex string to binary form. SYNOPSIS - scramble() - scrambled IN Scrambled message to check - message IN Original message which was scramble - hash_pass IN Password which should be used for scrambling - old_ver IN Forse old version random number generator + get_salt_from_password() + res OUT buf to hold password. Must be at least SHA1_HASH_SIZE + bytes long. + password IN 4.1.1 version value of user.password +*/ + +void get_salt_from_password(uint8 *hash_stage2, const char *password) +{ + hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2); +} - RETURN - 0 Password correct - !0 Password invalid +/* + Convert scrambled password from binary form to asciiz hex string. + SYNOPSIS + make_password_from_salt() + to OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes + salt IN password in salt format */ -my_bool check_scramble(const char *scrambled, const char *message, - ulong *hash_pass, my_bool old_ver) +void make_password_from_salt(char *to, const uint8 *hash_stage2) { - struct rand_struct rand_st; - ulong hash_message[2]; - char buff[16],*to,extra; /* Big enough for check */ - const char *pos; - char message_buffer[SCRAMBLE_LENGTH+1]; /* Copy of message */ - - /* We need to copy the message as this function can be called for MySQL 4.1 - scramble which is not zero ended and can have zeroes inside - We could just write zero to proper place in original message but - this would make it harder to understand code for next generations - */ - - memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */ - message_buffer[SCRAMBLE_LENGTH]=0; - - /* Check if this exactly N bytes. Overwise this is something fishy */ - if (strlen(message_buffer)!=SCRAMBLE_LENGTH) - return 1; /* Wrong password */ - - hash_password(hash_message,message_buffer); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); - to=buff; - for (pos=scrambled ; *pos ; pos++) - *to++=(char) (floor(my_rnd(&rand_st)*31)+64); - if (old_ver) - extra=0; - else - extra=(char) (floor(my_rnd(&rand_st)*31)); - to=buff; - while (*scrambled) - { - if (*scrambled++ != (char) (*to++ ^ extra)) - return 1; /* Wrong password */ - } - return 0; + *to++= PVERSION41_CHAR; + octet2hex(to, hash_stage2, SHA1_HASH_SIZE); } diff --git a/sql/slave.cc b/sql/slave.cc index c45c11f8bef..91376df5590 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1459,7 +1459,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, if (master_user) strmake(mi->user, master_user, sizeof(mi->user) - 1); if (master_password) - strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); + strmake(mi->password, master_password, SCRAMBLED_PASSWORD_CHAR_LENGTH); mi->port = master_port; mi->connect_retry = master_connect_retry; } @@ -1483,8 +1483,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, master_host) || init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, master_user) || - init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file, - master_password) || + init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1, + &mi->file, master_password) || init_intvar_from_file(&port, &mi->file, master_port) || init_intvar_from_file(&connect_retry, &mi->file, master_connect_retry)) diff --git a/sql/slave.h b/sql/slave.h index 429456eb0bb..d3565565ded 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -292,7 +292,7 @@ typedef struct st_master_info /* the variables below are needed because we can change masters on the fly */ char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; - char password[HASH_PASSWORD_LENGTH+1]; + char password[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; pthread_mutex_t data_lock,run_lock; pthread_cond_t data_cond,start_cond,stop_cond; THD *io_thd; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1bdca7167e8..bbc6b74c3a9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -68,11 +68,36 @@ static ulong get_sort(uint count,...); static void init_check_host(void); static ACL_USER *find_acl_user(const char *host, const char *user); static bool update_user_table(THD *thd, const char *host, const char *user, - const char *new_password); + const char *new_password, uint new_password_len); static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); +/* + Convert scrambled password to binary form, according to scramble type, + Binary form is stored in user.salt. +*/ + +static +void +set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) +{ + if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) + { + get_salt_from_password(acl_user->salt, password); + acl_user->salt_len= SCRAMBLE_LENGTH; + } + else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 + || password_len == 8 && protocol_version == 9) + { + get_salt_from_password_323((ulong *) acl_user->salt, password); + acl_user->salt_len= password_len/2; + } + else + acl_user->salt_len= 0; +} + + /* Read grant privileges from the privilege tables in the 'mysql' database. @@ -175,16 +200,19 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (table->field[2]->field_length == 8 && protocol_version == PROTOCOL_VERSION) { - sql_print_error( - "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */ + sql_print_error("Old 'user' table. " + "(Check README or the Reference manual). " + "Continuing --old-protocol"); /* purecov: tested */ protocol_version=9; /* purecov: tested */ } DBUG_PRINT("info",("user table fields: %d, password length: %d", table->fields, table->field[2]->field_length)); - if (table->field[2]->field_length < 45 && !use_old_passwords) + if (table->field[2]->field_length < 41 && !use_old_passwords) { - sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run"); + sql_print_error("mysql.user table is not updated to new password format; " + "Disabling new password usage until " + "mysql_fix_privilege_tables is run"); use_old_passwords= 1; } @@ -192,83 +220,88 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) while (!(read_record_info.read_record(&read_record_info))) { ACL_USER user; - uint length=0; - update_hostname(&user.host,get_field(&mem, table->field[0])); - user.user=get_field(&mem, table->field[1]); - user.password=get_field(&mem, table->field[2]); - if (user.password && (length=(uint) strlen(user.password)) == 8 && - protocol_version == PROTOCOL_VERSION) - { - sql_print_error( - "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)", - user.user ? user.user : ""); /* purecov: tested */ - } - else /* non empty and not short passwords */ - { - user.pversion=get_password_version(user.password); - /* Only passwords of specific lengths depending on version are allowed */ - if ( (!user.pversion && length % 8) || (user.pversion && length!=45 )) - { - sql_print_error( - "Found invalid password for user: '%s@%s'; Ignoring user", - user.user ? user.user : "", - user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ - continue; /* purecov: tested */ + update_hostname(&user.host, get_field(&mem, table->field[0])); + user.user= get_field(&mem, table->field[1]); + const char *password= get_field(&mem, 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 8: /* 3.20: to be removed */ + sql_print_error("Found old style password for user '%s'. " + "Ignoring user. (You may want to restart mysqld " + "using --old-protocol) ", + user.user ? user.user : ""); + break; + case 45: /* 4.1: to be removed */ + sql_print_error("Found 4.1 style password for user '%s'. " + "Ignoring user. " + "You should change password for this user.", + user.user ? user.user : ""); + break; + default: + sql_print_error("Found invalid password for user: '%s@%s'; " + "Ignoring user", user.user ? user.user : "", + user.host.hostname ? user.host.hostname : ""); + break; } } - get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3) & GLOBAL_ACLS; - user.sort=get_sort(2,user.host.hostname,user.user); - user.hostname_length= (user.host.hostname ? - (uint) strlen(user.host.hostname) : 0); - if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ - { - char *ssl_type=get_field(&mem, table->field[24]); - if (!ssl_type) - user.ssl_type=SSL_TYPE_NONE; - else if (!strcmp(ssl_type, "ANY")) - user.ssl_type=SSL_TYPE_ANY; - else if (!strcmp(ssl_type, "X509")) - user.ssl_type=SSL_TYPE_X509; - else /* !strcmp(ssl_type, "SPECIFIED") */ - user.ssl_type=SSL_TYPE_SPECIFIED; - - user.ssl_cipher= get_field(&mem, table->field[25]); - user.x509_issuer= get_field(&mem, table->field[26]); - user.x509_subject= get_field(&mem, table->field[27]); - - char *ptr = get_field(&mem, table->field[28]); - user.user_resource.questions=atoi(ptr); - ptr = get_field(&mem, table->field[29]); - user.user_resource.updates=atoi(ptr); - ptr = get_field(&mem, table->field[30]); - user.user_resource.connections=atoi(ptr); - if (user.user_resource.questions || user.user_resource.updates || - user.user_resource.connections) - mqh_used=1; - } - else + else // password is correct { - user.ssl_type=SSL_TYPE_NONE; - bzero(&(user.user_resource),sizeof(user.user_resource)); -#ifndef TO_BE_REMOVED - if (table->fields <= 13) - { // Without grant - if (user.access & CREATE_ACL) - user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + user.access= get_access(table,3) & GLOBAL_ACLS; + user.sort= get_sort(2,user.host.hostname,user.user); + user.hostname_length= (user.host.hostname ? + (uint) strlen(user.host.hostname) : 0); + if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ + { + char *ssl_type=get_field(&mem, table->field[24]); + if (!ssl_type) + user.ssl_type=SSL_TYPE_NONE; + else if (!strcmp(ssl_type, "ANY")) + user.ssl_type=SSL_TYPE_ANY; + else if (!strcmp(ssl_type, "X509")) + user.ssl_type=SSL_TYPE_X509; + else /* !strcmp(ssl_type, "SPECIFIED") */ + user.ssl_type=SSL_TYPE_SPECIFIED; + + user.ssl_cipher= get_field(&mem, table->field[25]); + user.x509_issuer= get_field(&mem, table->field[26]); + user.x509_subject= get_field(&mem, table->field[27]); + + char *ptr = get_field(&mem, table->field[28]); + user.user_resource.questions=atoi(ptr); + ptr = get_field(&mem, table->field[29]); + user.user_resource.updates=atoi(ptr); + ptr = get_field(&mem, table->field[30]); + user.user_resource.connections=atoi(ptr); + if (user.user_resource.questions || user.user_resource.updates || + user.user_resource.connections) + mqh_used=1; } - /* Convert old privileges */ - user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; - if (user.access & FILE_ACL) - user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; - if (user.access & PROCESS_ACL) - user.access|= SUPER_ACL | EXECUTE_ACL; + else + { + user.ssl_type=SSL_TYPE_NONE; + bzero(&(user.user_resource),sizeof(user.user_resource)); +#ifndef TO_BE_REMOVED + if (table->fields <= 13) + { // Without grant + if (user.access & CREATE_ACL) + user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; + } + /* Convert old privileges */ + user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; + if (user.access & FILE_ACL) + user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + if (user.access & PROCESS_ACL) + user.access|= SUPER_ACL | EXECUTE_ACL; #endif + } + VOID(push_dynamic(&acl_users,(gptr) &user)); + if (!user.host.hostname || user.host.hostname[0] == wild_many && + !user.host.hostname[1]) + allow_all_hosts=1; // Anyone can connect } - VOID(push_dynamic(&acl_users,(gptr) &user)); - if (!user.host.hostname || user.host.hostname[0] == wild_many && - !user.host.hostname[1]) - allow_all_hosts=1; // Anyone can connect } qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, sizeof(ACL_USER),(qsort_cmp) acl_compare); @@ -462,247 +495,203 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) /* - Prepare crypted scramble to be sent to the client -*/ - -void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) -{ - /* Binary password format to be used for generation*/ - char bin_password[SCRAMBLE41_LENGTH]; - /* Generate new long scramble for the thread */ - create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble); - thd->scramble[SCRAMBLE41_LENGTH]=0; - /* Get binary form, First 4 bytes of prepared scramble is salt */ - get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble, - (unsigned char*) bin_password); - /* Store "*" as identifier for old passwords */ - if (!acl_user->pversion) - prepared_scramble[0]='*'; - /* Finally encrypt password to get prepared scramble */ - password_crypt(thd->scramble, prepared_scramble+4, bin_password, - SCRAMBLE41_LENGTH); -} - - -/* - Get master privilges for user (priviliges for all tables). - Required before connecting to MySQL - - As we have 2 stage handshake now we cache user not to lookup - it second time. At the second stage we do not lookup user in case - we already know it; - + Seek ACL entry for a user, check password, SSL cypher, and if + everything is OK, update THD user data and USER_RESOURCES struct. + 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 + thd INOUT thread handle. If all checks are OK, + thd->priv_user, thd->master_access are updated. + thd->host, thd->ip, thd->user are used for checks. + mqh OUT user resources; on success mqh is reset, else + unchanged + passwd IN scrambled & crypted password, recieved from client + (to check): thd->scramble or thd->scramble_323 is + used to decrypt passwd, so they must contain + original random string, + passwd_len IN length of passwd, must be one of 0, 8, + SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH + old_version IN if old (3.20) protocol is used + RETURN VALUE + 0 success: thread data and mqh are updated + 1 user not found or authentification failure + -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format. */ -ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *message,char **priv_user, - char *priv_host, bool old_ver, USER_RESOURCES *mqh, - char *prepared_scramble, uint *cur_priv_version, - ACL_USER **cached_user) +int +acl_getroot(THD *thd, USER_RESOURCES *mqh, + const char *passwd, uint passwd_len, bool old_version) { - ulong user_access=NO_ACCESS; - *priv_user= (char*) user; - bool password_correct= 0; - int stage= (*cached_user != NULL); /* NULL passed as first stage */ - ACL_USER *acl_user= NULL; DBUG_ENTER("acl_getroot"); - bzero(mqh,sizeof(USER_RESOURCES)); - if (!initialized) - { - // If no data allow anything - DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */ + if (!initialized) /* if no data allow anything */ + { + DBUG_RETURN(1); } + + int res= 1; + VOID(pthread_mutex_lock(&acl_cache->lock)); /* - Get possible access from user_list. This is or'ed to others not - fully specified - - If we have cached user use it, in other case look it up. + 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 */ - if (stage && (*cur_priv_version == priv_version)) - acl_user= *cached_user; - else + ACL_USER *acl_user= 0; + for (uint i=0 ; i < acl_users.elements ; i++) { - for (uint i=0 ; i < acl_users.elements ; i++) + ACL_USER *user_i = dynamic_element(&acl_users,i,ACL_USER*); + if (!user_i->user || !strcmp(thd->user, user_i->user)) { - ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*); - if (!acl_user_search->user || !strcmp(user,acl_user_search->user)) + if (compare_hostname(&user_i->host, thd->host, thd->ip)) { - if (compare_hostname(&acl_user_search->host,host,ip)) + /* check password: it should be empty or valid */ + if (passwd_len == user_i->salt_len) { - /* Found mathing user */ - acl_user= acl_user_search; - /* Store it as a cache */ - *cached_user= acl_user; - *cur_priv_version= priv_version; - break; + if (user_i->salt_len == 0 || + user_i->salt_len == SCRAMBLE_LENGTH && + check_scramble(passwd, thd->scramble, user_i->salt) == 0 || + check_scramble_323(passwd, thd->scramble_323, + (ulong *) user_i->salt, old_version) == 0) + { + acl_user= user_i; + res= 0; + } } + else if (passwd_len == SCRAMBLE_LENGTH && + user_i->salt_len == SCRAMBLE_LENGTH_323) + res= -1; + /* linear search complete: */ + break; } } } - - /* Now we have acl_user found and may start our checks */ + /* + This was moved to separate tree because of heavy HAVE_OPENSSL case. + If acl_user is not null, res is 0. + */ if (acl_user) { - /* Password should present for both or absend for both */ - if (!acl_user->password && !*password) - password_correct=1; - else if (!acl_user->password || !*password) - { - *cached_user= 0; // Impossible to connect - } - else - { - /* New version password is checked differently */ - if (acl_user->pversion) - { - if (stage) /* We check password only on the second stage */ - { - if (!validate_password(password,message,acl_user->salt)) - password_correct=1; - } - else /* First stage - just prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - /* Old way to check password */ - else - { - /* Checking the scramble at any stage. First - old clients */ - if (!check_scramble(password,message,acl_user->salt, - (my_bool) old_ver)) - password_correct=1; - else if (!stage) /* Here if password incorrect */ - { - /* At the first stage - prepare scramble */ - prepare_scramble(thd,acl_user,prepared_scramble); - } - } - } - } - - /* If user not found password_correct will also be zero */ - if (!password_correct) - goto unlock_and_exit; - - /* OK. User found and password checked continue validation */ - + /* OK. User found and password checked continue validation */ #ifdef HAVE_OPENSSL - { - Vio *vio=thd->net.vio; - /* - 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 to connect */ - user_access=acl_user->access; - break; - case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ - 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_peer_certificate(vio->ssl_)) - user_access=acl_user->access; - break; - case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ + { + ulong user_access= NO_ACCESS; + Vio *vio=thd->net.vio; /* - 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. + 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 */ - if (vio_type(vio) != VIO_TYPE_SSL) - break; - if (acl_user->ssl_cipher) - { - DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", - acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))); - if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))) - user_access=acl_user->access; - else - { - if (global_system_variables.log_warnings) - sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'", - acl_user->ssl_cipher, - SSL_get_cipher(vio->ssl_)); - user_access=NO_ACCESS; - break; - } - } - /* Prepare certificate (if exists) */ - DBUG_PRINT("info",("checkpoint 1")); - X509* cert=SSL_get_peer_certificate(vio->ssl_); - DBUG_PRINT("info",("checkpoint 2")); - /* If X509 issuer is speified, 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_error("X509 issuer mismatch: should be '%s' but is '%s'", - acl_user->x509_issuer, ptr); - user_access=NO_ACCESS; - free(ptr); - 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_error("X509 subject mismatch: '%s' vs '%s'", - acl_user->x509_subject, ptr); - user_access=NO_ACCESS; - } - else - user_access=acl_user->access; - free(ptr); + switch (acl_user->ssl_type) { + case SSL_TYPE_NOT_SPECIFIED: // Impossible + case SSL_TYPE_NONE: /* SSL is not required to connect */ + user_access=acl_user->access; + break; + case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ + 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_peer_certificate(vio->ssl_)) + user_access=acl_user->access; + 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) + break; + if (acl_user->ssl_cipher) + { + DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", + acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))); + if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_))) + user_access=acl_user->access; + else + { + if (global_system_variables.log_warnings) + sql_print_error("X509 ciphers mismatch: should be '%s'" + "but is '%s'", acl_user->ssl_cipher, + SSL_get_cipher(vio->ssl_)); + user_access=NO_ACCESS; + break; + } + } + /* Prepare certificate (if exists) */ + DBUG_PRINT("info",("checkpoint 1")); + X509* cert=SSL_get_peer_certificate(vio->ssl_); + DBUG_PRINT("info",("checkpoint 2")); + /* If X509 issuer is speified, 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_error("X509 issuer mismatch: should be '%s' " + "but is '%s'", acl_user->x509_issuer, ptr); + user_access=NO_ACCESS; + free(ptr); + 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_error("X509 subject mismatch: '%s' vs '%s'", + acl_user->x509_subject, ptr); + user_access=NO_ACCESS; + } + else + user_access=acl_user->access; + free(ptr); + } + break; } - break; + /* end of SSL stuff: assign result */ + thd->master_access= user_access; } - } #else /* HAVE_OPENSSL */ - user_access=acl_user->access; + thd->master_access= acl_user->access; #endif /* HAVE_OPENSSL */ - *mqh=acl_user->user_resource; - if (!acl_user->user) - *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ - - if (acl_user->host.hostname) - strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME); - else - *priv_host= 0; + thd->priv_user= acl_user->user ? thd->user : (char *) ""; + *mqh= acl_user->user_resource; -unlock_and_exit: + if (acl_user->host.hostname) + strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); + else + *thd->priv_host= 0; + } VOID(pthread_mutex_unlock(&acl_cache->lock)); - DBUG_RETURN(user_access); + DBUG_RETURN(res); } @@ -713,8 +702,9 @@ static byte* check_get_key(ACL_USER *buff,uint *length, return (byte*) buff->host.hostname; } + static void acl_update_user(const char *user, const char *host, - const char *password, + const char *password, uint password_len, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, @@ -750,20 +740,9 @@ static void acl_update_user(const char *user, const char *host, acl_user->x509_subject= (x509_subject ? strdup_root(&mem,x509_subject) : 0); } - if (password) - { - if (!password[0]) /* If password is empty set it to null */ - { - acl_user->password=0; - acl_user->pversion=0; // just initialize - } - else - { - acl_user->password=(char*) ""; // Just point at something - get_salt_from_password(acl_user->salt,password); - acl_user->pversion=get_password_version(acl_user->password); - } - } + + set_user_salt(acl_user, password, password_len); + /* search complete: */ break; } } @@ -772,7 +751,7 @@ static void acl_update_user(const char *user, const char *host, static void acl_insert_user(const char *user, const char *host, - const char *password, + const char *password, uint password_len, enum SSL_type ssl_type, const char *ssl_cipher, const char *x509_issuer, @@ -783,7 +762,6 @@ static void acl_insert_user(const char *user, const char *host, ACL_USER acl_user; acl_user.user=strdup_root(&mem,user); update_hostname(&acl_user.host,strdup_root(&mem,host)); - acl_user.password=0; acl_user.access=privileges; acl_user.user_resource = *mqh; acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user); @@ -793,12 +771,8 @@ static void acl_insert_user(const char *user, const char *host, acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0; acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0; acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0; - if (password) - { - acl_user.password=(char*) ""; // Just point at something - get_salt_from_password(acl_user.salt,password); - acl_user.pversion=get_password_version(password); - } + + set_user_salt(&acl_user, password, password_len); VOID(push_dynamic(&acl_users,(gptr) &acl_user)); if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many @@ -1135,7 +1109,6 @@ bool check_change_password(THD *thd, const char *host, const char *user) bool change_password(THD *thd, const char *host, const char *user, char *new_password) { - uint length=0; DBUG_ENTER("change_password"); DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", host,user,new_password)); @@ -1144,37 +1117,27 @@ bool change_password(THD *thd, const char *host, const char *user, if (check_change_password(thd, host, user)) DBUG_RETURN(1); - /* - password should always be 0,16 or 45 chars; - Simple hack to avoid cracking - */ - length=(uint) strlen(new_password); - if (length != 45) - new_password[length & 16]=0; - VOID(pthread_mutex_lock(&acl_cache->lock)); ACL_USER *acl_user; - if (!(acl_user= find_acl_user(host,user))) + if (!(acl_user= find_acl_user(host, user))) { - send_error(thd, ER_PASSWORD_NO_MATCH); VOID(pthread_mutex_unlock(&acl_cache->lock)); + send_error(thd, ER_PASSWORD_NO_MATCH); DBUG_RETURN(1); } + /* update loaded acl entry: */ + uint new_password_len= new_password ? strlen(new_password) : 0; + set_user_salt(acl_user, new_password, new_password_len); + if (update_user_table(thd, acl_user->host.hostname ? acl_user->host.hostname : "", acl_user->user ? acl_user->user : "", - new_password)) + new_password, new_password_len)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ send_error(thd,0); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */ } - get_salt_from_password(acl_user->salt,new_password); - acl_user->pversion=get_password_version(new_password); - if (!new_password[0]) - acl_user->password=0; - else - acl_user->password=(char*) ""; // Point at something acl_cache->clear(1); // Clear locked hostname cache VOID(pthread_mutex_unlock(&acl_cache->lock)); @@ -1210,7 +1173,7 @@ find_acl_user(const char *host, const char *user) if (!acl_user->user && !user[0] || acl_user->user && !strcmp(user,acl_user->user)) { - if (compare_hostname(&(acl_user->host),host,host)) + if (compare_hostname(&acl_user->host,host,host)) { DBUG_RETURN(acl_user); } @@ -1280,7 +1243,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, ****************************************************************************/ static bool update_user_table(THD *thd, const char *host, const char *user, - const char *new_password) + const char *new_password, uint new_password_len) { TABLE_LIST tables; TABLE *table; @@ -1304,7 +1267,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, DBUG_RETURN(1); /* purecov: deadcode */ } store_record(table,record[1]); - table->field[2]->store(new_password,(uint) strlen(new_password), &my_charset_latin1); + table->field[2]->store(new_password, new_password_len, &my_charset_latin1); if ((error=table->file->update_row(table->record[1],table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: deadcode */ @@ -1352,24 +1315,24 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, { int error = -1; bool old_row_exists=0; - char *password,empty_string[1]; + char empty_string[]= { '\0' }; + char *password= empty_string; + uint password_len= 0; char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_user_table"); safe_mutex_assert_owner(&acl_cache->lock); - password=empty_string; - empty_string[0]=0; - if (combo.password.str && combo.password.str[0]) { - if ((combo.password.length != HASH_PASSWORD_LENGTH) - && combo.password.length != HASH_OLD_PASSWORD_LENGTH) + if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH && + combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { my_printf_error(ER_PASSWORD_NO_MATCH, "Password hash should be a %d-digit hexadecimal number", - MYF(0),HASH_PASSWORD_LENGTH); + MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); DBUG_RETURN(-1); } + password_len= combo.password.length; password=combo.password.str; } @@ -1394,17 +1357,20 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, goto end; } old_row_exists = 0; - restore_record(table,default_values); // cp empty row from default_values - table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); - table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1); - table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1); + restore_record(table,default_values); // cp empty row from default_values + table->field[0]->store(combo.host.str,combo.host.length, + &my_charset_latin1); + table->field[1]->store(combo.user.str,combo.user.length, + &my_charset_latin1); + table->field[2]->store(password, password_len, + &my_charset_latin1); } else { old_row_exists = 1; store_record(table,record[1]); // Save copy for update if (combo.password.str) // If password given - table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1); + table->field[2]->store(password, password_len, &my_charset_latin1); } /* Update table columns with new privileges */ @@ -1501,10 +1467,8 @@ end: if (!error) { acl_cache->clear(1); // Clear privilege cache - if (!combo.password.str) - password=0; // No password given on command if (old_row_exists) - acl_update_user(combo.user.str,combo.host.str,password, + acl_update_user(combo.user.str, combo.host.str, password, password_len, thd->lex.ssl_type, thd->lex.ssl_cipher, thd->lex.x509_issuer, @@ -1512,7 +1476,7 @@ end: &thd->lex.mqh, rights); else - acl_insert_user(combo.user.str,combo.host.str,password, + acl_insert_user(combo.user.str, combo.host.str, password, password_len, thd->lex.ssl_type, thd->lex.ssl_cipher, thd->lex.x509_issuer, @@ -2915,12 +2879,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append ("'@'",3); global.append(lex_user->host.str,lex_user->host.length); global.append ('\''); - if (acl_user->password) + if (acl_user->salt_len) { - char passd_buff[HASH_PASSWORD_LENGTH+1]; - make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion); + char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; + if (acl_user->salt_len == SCRAMBLE_LENGTH) + make_password_from_salt(passwd_buff, acl_user->salt); + else + make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt); global.append(" IDENTIFIED BY PASSWORD '",25); - global.append(passd_buff); + global.append(passwd_buff); global.append('\''); } /* "show grants" SSL related stuff */ diff --git a/sql/sql_acl.h b/sql/sql_acl.h index e6c6771253c..3370797820a 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -111,9 +111,9 @@ public: acl_host_and_ip host; uint hostname_length; USER_RESOURCES user_resource; - char *user,*password; - ulong salt[6]; // New password has longer length - uint8 pversion; // password version + char *user; + uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form + uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1 enum SSL_type ssl_type; const char *ssl_cipher, *x509_issuer, *x509_subject; }; @@ -135,11 +135,8 @@ void acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db); -ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *scramble, - char **priv_user, char *priv_host, - bool old_ver, USER_RESOURCES *max,char* prepared_scramble, - uint *cur_priv_version, ACL_USER **cached_user); +int acl_getroot(THD *thd, USER_RESOURCES *mqh, + const char *passwd, uint passwd_len, bool old_ver); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, const char *host, const char *user); bool change_password(THD *thd, const char *host, const char *user, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c233ffd422a..ebb3e819ddc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -139,6 +139,7 @@ THD::THD():user_time(0), is_fatal_error(0), set_query_id=1; db_access=NO_ACCESS; version=refresh_version; // For boot + *scramble= *scramble_323= '\0'; init(); /* Initialize sub structures */ diff --git a/sql/sql_class.h b/sql/sql_class.h index ccfe2555518..d962cc8086e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -529,10 +529,16 @@ public: enum_tx_isolation session_tx_isolation; /* for user variables replication*/ DYNAMIC_ARRAY user_var_events; - // extend scramble to handle new auth - char scramble[SCRAMBLE41_LENGTH+1]; - // old scramble is needed to handle old clients - char old_scramble[SCRAMBLE_LENGTH+1]; + + /* scramble - random string sent to client on handshake */ + char scramble[SCRAMBLE_LENGTH+1]; + /* + The same as scramble but for old password checking routines. It always + contains first N bytes of scramble. + See check_connection() at sql_parse.cc for authentification details. + */ + char scramble_323[SCRAMBLE_LENGTH_323+1]; + uint8 query_cache_type; // type of query cache processing bool slave_thread; bool set_query_id,locked,count_cuted_fields,some_tables_deleted; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5070466007e..384ec2bd4dd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -178,152 +178,119 @@ end: /* - Check if user is ok - + Check if user exist and password supplied is correct. SYNOPSIS check_user() - thd Thread handle - command Command for connection (for log) - user Name of user trying to connect - passwd Scrambled password sent from client - db Database to connect to - check_count If set to 1, don't allow too many connection - simple_connect If 1 then client is of old type and we should connect - using the old method (no challange) - do_send_error Set to 1 if we should send error to user - prepared_scramble Buffer to store hash password of new connection - had_password Set to 1 if the user gave a password - cur_priv_version Check flag to know if someone flushed the privileges - since last code - hint_user Pointer used by acl_getroot() to remmeber user for - next call - - RETURN - 0 ok - thd->user, thd->master_access, thd->priv_user, thd->db and - thd->db_access are updated - 1 Access denied; Error sent to client - -1 If do_send_error == 1: Failed connect, error sent to client - If do_send_error == 0: Prepare for stage of connect + thd INOUT thread handle, thd->{host,user,ip} are used + command IN originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + passwd IN scrambled password recieved from client + passwd_len IN length of scrambled password + db IN database name to connect to, may be NULL + check_count IN dont know exactly + Note, that host, user and passwd may point to communication buffer. + Current implementation does not depened on that, but future changes + should be done with this in mind. + RETURN VALUE + 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and + thd->db_access are updated; OK is sent to client; + 1 access denied or internal error; error is sent to client + Note, that this return semantics differs from check_connection, + which returns -1 if message was already sent. + -1 acl entry for this user contains old scramble, but passwd contains + new one, error is not sent to client */ -static int check_user(THD *thd,enum_server_command command, const char *user, - const char *passwd, const char *db, bool check_count, - bool simple_connect, bool do_send_error, - char *prepared_scramble, bool had_password, - uint *cur_priv_version, ACL_USER** hint_user) +static int check_user(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count) { - thd->db=0; - thd->db_length=0; - USER_RESOURCES ur; - char tmp_passwd[SCRAMBLE41_LENGTH]; DBUG_ENTER("check_user"); - - /* - Move password to temporary buffer as it may be stored in communication - buffer - */ - strmake(tmp_passwd, passwd, sizeof(tmp_passwd)); - passwd= tmp_passwd; // Use local copy - - /* We shall avoid dupplicate user allocations here */ - if (!thd->user && !(thd->user = my_strdup(user, MYF(0)))) - { - send_error(thd,ER_OUT_OF_RESOURCES); - DBUG_RETURN(1); - } - thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, - passwd, thd->scramble, - &thd->priv_user, thd->priv_host, - (protocol_version == 9 || - !(thd->client_capabilities & - CLIENT_LONG_PASSWORD)), - &ur,prepared_scramble, - cur_priv_version,hint_user); - - DBUG_PRINT("info", - ("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'", - thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->user, thd->priv_user, - had_password ? "yes": "no", - thd->master_access, thd->db ? thd->db : "*none*")); /* - In case we're going to retry we should not send error message at this - point + Why this is set here? - probably to reset current DB to 'no database + selected' in case of 'change user' failure. */ - if (thd->master_access & NO_ACCESS) + thd->db= 0; + thd->db_length= 0; + + USER_RESOURCES ur; + int res= acl_getroot(thd, &ur, passwd, passwd_len, + protocol_version == 9 || + !(thd->client_capabilities & CLIENT_LONG_PASSWORD)); + if (res == 0 && !(thd->master_access & NO_ACCESS)) // authentification is OK { - if (do_send_error || !had_password || !*hint_user) + DBUG_PRINT("info", + ("Capabilities: %d packet_length: %ld Host: '%s' " + "Login user: '%s' Priv_user: '%s' Using password: %s " + "Access: %u db: '%s'", + thd->client_capabilities, thd->max_client_packet_length, + thd->host_or_ip, thd->user, thd->priv_user, + passwd_len ? "yes": "no", + thd->master_access, thd->db ? thd->db : "*none*")); + + if (check_count) { - DBUG_PRINT("info",("Access denied")); - /* - Old client should get nicer error message if password version is - not supported - */ - if (simple_connect && *hint_user && (*hint_user)->pversion) - { - net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); - mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE)); + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool count_ok= thread_count < max_connections + delayed_insert_threads || + thd->master_access & SUPER_ACL; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!count_ok) + { // too many connections + send_error(thd, ER_CON_COUNT_ERROR); + DBUG_RETURN(1); } - else - { - net_printf(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); - mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, - had_password ? ER(ER_YES) : ER(ER_NO)); - } - DBUG_RETURN(1); // Error already given } - DBUG_PRINT("info",("Prepare for second part of handshake")); - DBUG_RETURN(-1); // no report error in special handshake - } - if (check_count) - { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool tmp=(thread_count - delayed_insert_threads >= max_connections && - !(thd->master_access & SUPER_ACL)); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - if (tmp) - { // Too many connections - send_error(thd, ER_CON_COUNT_ERROR); + /* Why logging is performed before all checks've passed? */ + mysql_log.write(thd,command, + (thd->priv_user == thd->user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + thd->user, thd->host_or_ip, + db ? db : (char*) ""); + + /* Why is it set here? */ + thd->db_access=0; + + /* Don't allow user to connect if he has done too many queries */ + if ((ur.questions || ur.updates || ur.connections) && + get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) + DBUG_RETURN(1); + if (thd->user_connect && thd->user_connect->user_resources.connections && + check_for_max_user_connections(thd, thd->user_connect)) DBUG_RETURN(1); + + /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ + if (db && db[0]) + { + if (mysql_change_db(thd, db)) + { + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(1); + } } + else + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages + /* Ready to handle queries */ } - mysql_log.write(thd,command, - (thd->priv_user == thd->user ? - (char*) "%s@%s on %s" : - (char*) "%s@%s as anonymous on %s"), - user, - thd->host_or_ip, - db ? db : (char*) ""); - thd->db_access=0; - /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.connections) && - get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) - DBUG_RETURN(1); - if (thd->user_connect && thd->user_connect->user_resources.connections && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(1); - - if (db && db[0]) + else if (res != -1) // authentication failure { - int error= test(mysql_change_db(thd,db)); - if (error && thd->user_connect) - decrease_user_connections(thd->user_connect); - DBUG_RETURN(error); - } - send_ok(thd); // Ready to handle questions - thd->password= test(passwd[0]); // Remember for error messages - DBUG_RETURN(0); // ok + net_printf(thd, ER_ACCESS_DENIED_ERROR, + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + } + DBUG_RETURN(res); } - /* Check for maximum allowable user connections, if the mysqld server is started with corresponding variable that is greater then 0. @@ -525,48 +492,93 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0) /* - Check connnectionn and get priviliges - + Perform check for scrambled password, re-request scrambled password + from client if necessary. See also help for check_user. SYNOPSIS - check_connections - thd Thread handle + authenticate() + RETURN VALUE + 0 success, OK sent to client + -1 error, sent to client + > 0 error, not sent to client +*/ + +static +int +authenticate(THD *thd, enum enum_server_command command, + const char *passwd, uint passwd_len, const char *db, + bool check_count) +{ + if (passwd_len != 0 && + passwd_len != SCRAMBLE_LENGTH && + passwd_len != SCRAMBLE_LENGTH_323) + return 1; + int res= check_user(thd, COM_CONNECT, passwd, passwd_len, db, check_count); + if (res < 0) + { + /* + This happens when client (new) sends password scrambled with + scramble(), but database holds old value (scrambled with + scramble_323()). Here we please client to send scrambled_password + in old format. + */ + char buff[NAME_LEN + 1]; + /* save db because network buffer is to hold new packet */ + if (db) + { + strmake(buff, db, NAME_LEN); + db= buff; + } + NET *net= &thd->net; + if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) || + net_flush(net) || + my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very + { // specific packet size + inc_host_errors(&thd->remote.sin_addr); + return ER_HANDSHAKE_ERROR; + } + /* Final attempt to check the user based on reply */ + /* So as passwd is short, errcode is always sent to user and res >= 0 */ + res= check_user(thd, COM_CONNECT, (char *) net->read_pos, + SCRAMBLE_LENGTH_323, db, check_count); + } + return res > 0 ? -1 : 0; +} + +/* + Perform handshake, authorize client and update thd ACL variables. + SYNOPSIS + check_connection() + thd INOUT thread handle RETURN - 0 ok - -1 Error, which is sent to user - > 0 Error code (not sent to user) + 0 success, OK is sent to user + -1 error, which is sent to user + > 0 error code (not sent to user) */ #ifndef EMBEDDED_LIBRARY static int -check_connections(THD *thd) +check_connection(THD *thd) { - int res; - uint connect_errors=0; - uint cur_priv_version; - bool using_password; + uint connect_errors= 0; NET *net= &thd->net; - char *end, *user, *passwd, *db; - char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */ - ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */ - DBUG_PRINT("info",("New connection received on %s", - vio_description(net->vio))); - - /* Remove warning from valgrind. TODO: Fix it in password.c */ - bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble)); + + DBUG_PRINT("info", + ("New connection received on %s", vio_description(net->vio))); + if (!thd->host) // If TCP/IP connection { char ip[30]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) return (ER_BAD_HOST_ERROR); - if (!(thd->ip = my_strdup(ip,MYF(0)))) + if (!(thd->ip= my_strdup(ip,MYF(0)))) return (ER_OUT_OF_RESOURCES); - thd->host_or_ip=thd->ip; + thd->host_or_ip= thd->ip; #if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) /* Fast local hostname resolve for Win32 */ if (!strcmp(thd->ip,"127.0.0.1")) - thd->host=(char*) localhost; + thd->host= (char *) localhost; else #endif { @@ -595,15 +607,16 @@ check_connections(THD *thd) DBUG_PRINT("info",("Host: %s",thd->host)); thd->host_or_ip= thd->host; thd->ip= 0; - bzero((char*) &thd->remote,sizeof(struct sockaddr)); + bzero((char*) &thd->remote, sizeof(struct sockaddr)); } /* Ensure that wrong hostnames doesn't cause buffer overflows */ vio_keepalive(net->vio, TRUE); - ulong pkt_len=0; + ulong pkt_len= 0; + char *end; { /* buff[] needs to big enough to hold the server_version variable */ - char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64]; + char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); @@ -617,19 +630,36 @@ check_connections(THD *thd) client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */ #endif /* HAVE_OPENSSL */ - end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1; - int4store((uchar*) end,thd->thread_id); - end+=4; - memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1); - end+=SCRAMBLE_LENGTH +1; - int2store(end,client_flags); - end[2]=(char) default_charset_info->number; - int2store(end+3,thd->server_status); - bzero(end+5,13); - end+=18; + end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; + int4store((uchar*) end, thd->thread_id); + end+= 4; + /* + So as check_connection is the only entry point to authorization + procedure, scramble is set here. This gives us new scramble for + each handshake. + */ + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); + strmake(thd->scramble_323, thd->scramble, SCRAMBLE_LENGTH_323); - // At this point we write connection message and read reply - if (net_write_command(net,(uchar) protocol_version, "", 0, buff, + /* + Old clients does not understand long scrambles, but can ignore packet + tail: that's why first part of scramble is placed here, and second + part at the end of packet. + */ + end= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1; + + int2store(end, client_flags); + /* write server characteristics: up to 16 bytes allowed */ + end[2]=(char) default_charset_info->number; + int2store(end+3, thd->server_status); + bzero(end+5, 13); + end+= 18; + /* write scramble tail */ + end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323, + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1; + + /* At this point we write connection message and read reply */ + if (net_write_command(net, (uchar) protocol_version, "", 0, buff, (uint) (end-buff)) || (pkt_len= my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) @@ -702,7 +732,7 @@ check_connections(THD *thd) return(ER_HANDSHAKE_ERROR); } DBUG_PRINT("info", ("Reading user information over SSL layer")); - if ((pkt_len=my_net_read(net)) == packet_error || + if ((pkt_len= my_net_read(net)) == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE) { DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)", @@ -719,16 +749,7 @@ check_connections(THD *thd) return(ER_HANDSHAKE_ERROR); } - user= end; - passwd= strend(user)+1; - db=0; - using_password= test(passwd[0]); - if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) - db=strend(passwd)+1; - - /* We can get only old hash at this point */ - if (using_password && strlen(passwd) != SCRAMBLE_LENGTH) - return ER_HANDSHAKE_ERROR; + /* why has it been put here? */ if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; @@ -737,60 +758,19 @@ check_connections(THD *thd) net->return_status= &thd->server_status; net->read_timeout=(uint) thd->variables.net_read_timeout; - /* Simple connect only for old clients. New clients always use secure auth */ - bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION)); - - /* Check user permissions. If password failure we'll get scramble back */ - if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect, - simple_connect, prepared_scramble, using_password, - &cur_priv_version, - &cached_user)) < 0) - { - /* Store current used and database as they are erased with next packet */ - char tmp_user[USERNAME_LENGTH+1]; - char tmp_db[NAME_LEN+1]; - - /* If the client is old we just have to return error */ - if (simple_connect) - return -1; + char *user= end; + char *passwd= strend(user)+1; + uint passwd_len= strlen(passwd); - DBUG_PRINT("info",("password challenge")); + char *db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? + passwd+passwd_len+1 : 0; - tmp_user[0]= tmp_db[0]= 0; - if (user) - strmake(tmp_user,user,USERNAME_LENGTH); - if (db) - strmake(tmp_db,db,NAME_LEN); - - /* Write hash and encrypted scramble to client */ - if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || - net_flush(net)) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* Reading packet back */ - if ((pkt_len= my_net_read(net)) == packet_error) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* We have to get very specific packet size */ - if (pkt_len != SCRAMBLE41_LENGTH) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* Final attempt to check the user based on reply */ - if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos, - tmp_db, 1, 0, 1, prepared_scramble, using_password, - &cur_priv_version, - &cached_user)) - return -1; - } - else if (res) - return -1; // Error sent from check_user() - return 0; + if (thd->user) + x_free(thd->user); + thd->user= my_strdup(user, MYF(0)); + if (!thd->user) + return(ER_OUT_OF_RESOURCES); + return authenticate(thd, COM_CONNECT, passwd, passwd_len, db, true); } @@ -847,7 +827,7 @@ pthread_handler_decl(handle_one_connection,arg) NET *net= &thd->net; thd->thread_stack= (char*) &thd; - if ((error=check_connections(thd))) + if ((error=check_connection(thd))) { // Wrong permissions if (error > 0) net_printf(thd,error,thd->host_or_ip); @@ -1152,116 +1132,60 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_CHANGE_USER: { thd->change_user(); - thd->clear_error(); // If errors from rollback + thd->clear_error(); // if errors from rollback - statistic_increment(com_other,&LOCK_status); - char *user= (char*) packet; + statistic_increment(com_other, &LOCK_status); + char *user= (char*) packet; char *passwd= strend(user)+1; - char *db= strend(passwd)+1; + uint passwd_len= strlen(passwd); + char *db= passwd + passwd_len + 1; - /* Save user and privileges */ - uint save_master_access=thd->master_access; - uint save_db_access= thd->db_access; - uint save_db_length= thd->db_length; - char *save_user= thd->user; - thd->user=NULL; /* Needed for check_user to allocate new user */ - char *save_priv_user= thd->priv_user; - char *save_db= thd->db; - USER_CONN *save_uc= thd->user_connect; - bool simple_connect; - bool using_password; - char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */ - char tmp_user[USERNAME_LENGTH+1]; - char tmp_db[NAME_LEN+1]; - ACL_USER* cached_user ; /* Cached user */ - uint cur_priv_version; /* Cached grant version */ - int res; - ulong pkt_len= 0; /* Length of reply packet */ - - bzero((char*) prepared_scramble, sizeof(prepared_scramble)); /* Small check for incomming packet */ - if ((uint) ((uchar*) db - net->read_pos) > packet_length) - goto restore_user_err; - - /* Now we shall basically perform authentication again */ - - /* We can get only old hash at this point */ - if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH) - goto restore_user_err; - - cached_user= NULL; - - /* Simple connect only for old clients. New clients always use sec. auth*/ - simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION)); - - /* Store information if we used password. passwd will be dammaged */ - using_password=test(passwd[0]); - - if (simple_connect) /* Restore scramble for old clients */ - memcpy(thd->scramble,thd->old_scramble,9); + { + send_error(thd, ER_UNKNOWN_COM_ERROR); + break; + } - /* - Check user permissions. If password failure we'll get scramble back - Do not retry if we already have sent error (result>0) - */ - if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, - simple_connect, simple_connect, prepared_scramble, - using_password, &cur_priv_version, &cached_user)) < 0) + /* Save user and privileges */ + uint save_master_access= thd->master_access; + uint save_db_access= thd->db_access; + uint save_db_length= thd->db_length; + char *save_user= thd->user; + char *save_priv_user= thd->priv_user; + char *save_db= thd->db; + USER_CONN *save_uc= thd->user_connect; + thd->user= my_strdup(user, MYF(0)); + if (!thd->user) { - /* If the client is old we just have to have auth failure */ - if (simple_connect) - goto restore_user; /* Error is already reported */ - - /* Store current used and database as they are erased with next packet */ - tmp_user[0]= tmp_db[0]= 0; - if (user) - strmake(tmp_user,user,USERNAME_LENGTH); - if (db) - strmake(tmp_db,db,NAME_LEN); - - /* Write hash and encrypted scramble to client */ - if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || - net_flush(net)) - goto restore_user_err; - - /* Reading packet back */ - if ((pkt_len=my_net_read(net)) == packet_error) - goto restore_user_err; - - /* We have to get very specific packet size */ - if (pkt_len != SCRAMBLE41_LENGTH) - goto restore_user; - - /* Final attempt to check the user based on reply */ - if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos, - tmp_db, 0, 0, 1, prepared_scramble, using_password, - &cur_priv_version, &cached_user)) - goto restore_user; + thd->user= save_user; + send_error(thd, ER_OUT_OF_RESOURCES); + break; } - else if (res) - goto restore_user; - - /* Finally we've authenticated new user */ - if (max_connections && save_uc) - decrease_user_connections(save_uc); - x_free((gptr) save_db); - x_free((gptr) save_user); - thd->password=using_password; - break; - /* Bad luck we shall restore old user */ -restore_user_err: - send_error(thd, ER_UNKNOWN_COM_ERROR); + int res= authenticate(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); -restore_user: - x_free(thd->user); - thd->master_access=save_master_access; - thd->db_access=save_db_access; - thd->db=save_db; - thd->db_length=save_db_length; - thd->user=save_user; - thd->priv_user=save_priv_user; + if (res) + { + /* authentification failure, we shall restore old user */ + if (res > 0) + send_error(thd, ER_UNKNOWN_COM_ERROR); + x_free(thd->user); + thd->user= save_user; + thd->priv_user= save_priv_user; + thd->master_access= save_master_access; + thd->db_access= save_db_access; + thd->db= save_db; + thd->db_length= save_db_length; + } + else + { + /* we've authenticated new user */ + if (max_connections && save_uc) + decrease_user_connections(save_uc); + x_free((gptr) save_db); + x_free((gptr) save_user); + } break; } #endif /* EMBEDDED_LIBRARY */ @@ -3158,7 +3082,7 @@ error: Check grants for commands which work only with one table and all other tables belong to subselects. - SYNOPSYS + SYNOPSIS single_table_command_access() thd - Thread handler privilege - asked privelage diff --git a/sql/sql_repl.h b/sql/sql_repl.h index e3d600b9798..b53551845bc 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -7,7 +7,7 @@ typedef struct st_slave_info uint32 rpl_recovery_rank, master_id; char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; - char password[HASH_PASSWORD_LENGTH+1]; + char password[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; uint16 port; THD* thd; } SLAVE_INFO; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1d605abe8a3..c8c9eb97a6a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2515,9 +2515,10 @@ simple_expr: | NOW_SYM '(' expr ')' { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' - { $$= new Item_func_password($3); } - | PASSWORD '(' expr ',' expr ')' - { $$= new Item_func_password($3,$5); } + { + $$= use_old_passwords ? (Item *) new Item_func_old_password($3) : + (Item *) new Item_func_password($3); + } | POINT_SYM '(' expr ',' expr ')' { $$= new Item_func_point($3,$5); } | POINTFROMTEXT '(' expr ')' @@ -4604,13 +4605,22 @@ text_or_password: { if (!$3.length) $$=$3.str; - else + else if (use_old_passwords) { - char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); - make_scrambled_password(buff,$3.str,use_old_passwords, - &YYTHD->rand); + char *buff= (char *) + YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, $3.str); $$=buff; } + else + { + char *buff= (char *) + YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, $3.str); + $$=buff; + } } ; @@ -4918,14 +4928,24 @@ grant_user: $$=$1; $1->password=$4; if ($4.length) { - char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1); - if (buff) - { - make_scrambled_password(buff,$4.str,use_old_passwords, - &YYTHD->rand); - $1->password.str=buff; - $1->password.length=HASH_PASSWORD_LENGTH; - } + if (use_old_passwords) + { + char *buff= + (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, $4.str); + $1->password.str= buff; + $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; + } + else + { + char *buff= + (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, $4.str); + $1->password.str= buff; + $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH; + } } } | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING -- cgit v1.2.1 From ccbcf1c9da89eaee2dfb4219da1d86b6f590ac20 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jul 2003 20:52:04 +0400 Subject: Bug fixes for authentication OLD_PASSWORD made a keyword to allow set password=old_password('abc') constructions. BitKeeper/etc/ignore: Added BitKeeper/post-commit BitKeeper/post-commit-manual build_tags.sh tests/connect_test BUILD/compile-pentium-maintainer to the ignore list include/mysql_com.h: scramble return type changed to void as now it's not used libmysql/libmysql.c: fixed bug with with failed authentification when scramble contained zero byte sql-common/client.c: applied patch from Lycos team fixed bug with scramble containing zero byte sql/item_create.cc: removed create_func_old_password, create_func_password as they are not used any more sql/item_create.h: removed create_func_old_password, create_func_password as they are not used any more sql/item_strfunc.cc: Added alloc() function to Item_func_password, Item_func_old_password, which is used in sql_yacc.yy sql/item_strfunc.h: Added alloc() function to Item_func_password, Item_func_old_password, which is used in sql_yacc.yy sql/lex.h: OLD_PASSWORD now is keyword, to allow statements like set password=old_password('abc') sql/password.c: fixed scramble return value trailing zero now is not written sql/sql_acl.cc: incorporated patch from Lycos team 41 replaced with constant acl_getroot rewritten to support ER_AUTH_... error sql/sql_parse.cc: authenticate merged with check_user check_user return values reversed, support for ER_AUTH in check_user.added sql/sql_yacc.yy: OLD_PASSWORD now is keyword, to allow statements like set password=old_password('abc') --- .bzrignore | 5 ++ include/mysql_com.h | 2 +- libmysql/libmysql.c | 18 ++-- sql-common/client.c | 24 ++--- sql/item_create.cc | 12 --- sql/item_create.h | 2 - sql/item_strfunc.cc | 16 ++++ sql/item_strfunc.h | 3 +- sql/lex.h | 2 +- sql/password.c | 12 +-- sql/sql_acl.cc | 9 +- sql/sql_parse.cc | 250 ++++++++++++++++++++++++++-------------------------- sql/sql_yacc.yy | 37 ++++---- 13 files changed, 201 insertions(+), 191 deletions(-) diff --git a/.bzrignore b/.bzrignore index a23384d4170..7c0a871a951 100644 --- a/.bzrignore +++ b/.bzrignore @@ -624,3 +624,8 @@ vio/test-sslserver vio/viotest-ssl start_mysqld.sh mysys/main.cc +BitKeeper/post-commit +BitKeeper/post-commit-manual +build_tags.sh +tests/connect_test +BUILD/compile-pentium-maintainer diff --git a/include/mysql_com.h b/include/mysql_com.h index c1f18160667..784a7782855 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -327,7 +327,7 @@ void get_salt_from_password_323(unsigned long *res, const char *password); void make_password_from_salt_323(char *to, const unsigned long *salt); void make_scrambled_password(char *to, const char *password); -char *scramble(char *to, const char *message, const char *password); +void scramble(char *to, const char *message, const char *password); my_bool check_scramble(const char *reply, const char *message, const unsigned char *hash_stage2); void get_salt_from_password(unsigned char *res, const char *password); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 6bc38abb060..8b83343df8f 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -619,16 +619,20 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, /* write scrambled password according to server capabilities */ if (passwd[0]) { - /* Write NULL-terminated scrambled password: */ - end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? - scramble(end, mysql->scramble, passwd) : - scramble_323(end, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)); + if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + { + *end++= SCRAMBLE_LENGTH; + scramble(end, mysql->scramble, passwd); + end+= SCRAMBLE_LENGTH; + } + else + end= scramble_323(end, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)) + 1; } else - *end= '\0'; // empty password + *end++= '\0'; // empty password /* Add database if needed */ - end=strmov(end+1,db ? db : ""); + end= strmov(end, db ? db : "") + 1; /* Write authentication package */ simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); diff --git a/sql-common/client.c b/sql-common/client.c index 35dea62edc3..efb71021f8d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1823,7 +1823,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, mysql->server_status, client_flag)); /* This needs to be changed as it's not useful with big packets */ if (user && user[0]) - strmake(end,user,32); /* Max user name */ + strmake(end,user,USERNAME_LENGTH); /* Max user name */ else read_user_name((char*) end); @@ -1835,21 +1835,25 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, end= strend(end) + 1; if (passwd[0]) { - /* Write NULL-terminated scrambled password: */ - end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? - scramble(end, mysql->scramble, passwd) : - scramble_323(end, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)); + if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) + { + *end++= SCRAMBLE_LENGTH; + scramble(end, mysql->scramble, passwd); + end+= SCRAMBLE_LENGTH; + } + else + end= scramble_323(end, mysql->scramble_323, passwd, + (my_bool) (mysql->protocol_version == 9)) + 1; } else - *end= '\0'; /* empty password */ + *end++= '\0'; /* empty password */ /* Add database if needed */ if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) { - end=strmake(end+1,db,NAME_LEN); - mysql->db=my_strdup(db,MYF(MY_WME)); - db=0; + end= strmake(end, db, NAME_LEN) + 1; + mysql->db= my_strdup(db,MYF(MY_WME)); + db= 0; } /* Write authentication package */ if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) diff --git a/sql/item_create.cc b/sql/item_create.cc index 90f42cee959..fbb26e83dfd 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -52,13 +52,6 @@ Item *create_func_ord(Item* a) return new Item_func_ord(a); } -Item *create_func_old_password(Item* a) -{ - return new Item_func_old_password(a); -} - - - Item *create_func_asin(Item* a) { return new Item_func_asin(a); @@ -332,11 +325,6 @@ Item *create_func_quarter(Item* a) return new Item_func_quarter(a); } -Item *create_func_password(Item* a) -{ - return new Item_func_password(a); -} - Item *create_func_radians(Item *a) { return new Item_func_units((char*) "radians",a,M_PI/180,0.0); diff --git a/sql/item_create.h b/sql/item_create.h index 4151f59a87f..2872451c034 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -69,14 +69,12 @@ Item *create_func_monthname(Item* a); Item *create_func_nullif(Item* a, Item *b); Item *create_func_oct(Item *); Item *create_func_ord(Item* a); -Item *create_func_old_password(Item* a); Item *create_func_period_add(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b); Item *create_func_pi(void); Item *create_func_pow(Item* a, Item *b); Item *create_func_current_user(void); Item *create_func_quarter(Item* a); -Item *create_func_password(Item* a); Item *create_func_radians(Item *a); Item *create_func_release_lock(Item* a); Item *create_func_repeat(Item* a, Item *b); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f8488565b75..def465363fe 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1360,6 +1360,14 @@ String *Item_func_password::val_str(String *str) return str; } +char *Item_func_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); + if (buff) + make_scrambled_password(buff, password); + return buff; +} + /* Item_func_old_password */ String *Item_func_old_password::val_str(String *str) @@ -1374,6 +1382,14 @@ String *Item_func_old_password::val_str(String *str) return str; } +char *Item_func_old_password::alloc(THD *thd, const char *password) +{ + char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); + if (buff) + make_scrambled_password_323(buff, password); + return buff; +} + #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 11f5a66b3d1..3e0239cf76a 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -270,6 +270,7 @@ public: String *val_str(String *str); void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } const char *func_name() const { return "password"; } + static char *alloc(THD *thd, const char *password); }; @@ -288,7 +289,7 @@ public: String *val_str(String *str); void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } const char *func_name() const { return "old_password"; } - unsigned int size_of() { return sizeof(*this);} + static char *alloc(THD *thd, const char *password); }; diff --git a/sql/lex.h b/sql/lex.h index bb6e7a81ab4..f105fd4d9c8 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -284,6 +284,7 @@ static SYMBOL symbols[] = { { "NULL", SYM(NULL_SYM),0,0}, { "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "OFFSET", SYM(OFFSET_SYM),0,0}, + { "OLD_PASSWORD", SYM(OLD_PASSWORD),0,0}, { "ON", SYM(ON),0,0}, { "OPEN", SYM(OPEN_SYM),0,0}, { "OPTIMIZE", SYM(OPTIMIZE),0,0}, @@ -577,7 +578,6 @@ static SYMBOL sql_functions[] = { { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)}, { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)}, { "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, - { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)}, { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, diff --git a/sql/password.c b/sql/password.c index be6514d89c6..bfdb453af01 100644 --- a/sql/password.c +++ b/sql/password.c @@ -446,22 +446,20 @@ make_scrambled_password(char *to, const char *password) Produce an obscure octet sequence from password and random string, recieved from the server. This sequence corresponds to the password, but password can not be easily restored from it. The sequence - is then sent to the server for validation. Trailing zero is stored in - the buf. + is then sent to the server for validation. Trailing zero is not stored + in the buf as it is not needed. This function is used by client to create authenticated reply to the server's greeting. SYNOPSIS scramble() buf OUT store scrambled string here. The buf must be at least - SHA1_HASH_SIZE+1 bytes long. + SHA1_HASH_SIZE bytes long. message IN random message, must be exactly SCRAMBLE_LENGTH long and NULL-terminated. password IN users' password - RETURN VALUE - end of scrambled string */ -char * +void scramble(char *to, const char *message, const char *password) { SHA1_CONTEXT sha1_context; @@ -483,8 +481,6 @@ scramble(char *to, const char *message, const char *password) /* xor allows 'from' and 'to' overlap: lets take advantage of it */ sha1_result(&sha1_context, (uint8 *) to); my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH); - to[SHA1_HASH_SIZE]= '\0'; - return to + SHA1_HASH_SIZE; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index bbc6b74c3a9..f88799c2843 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -51,7 +51,7 @@ static byte* acl_entry_get_key(acl_entry *entry,uint *length, return (byte*) entry->key; } -#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17) +#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+USERNAME_LENGTH+1) static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs; static MEM_ROOT mem, memex; @@ -208,7 +208,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) DBUG_PRINT("info",("user table fields: %d, password length: %d", table->fields, table->field[2]->field_length)); - if (table->field[2]->field_length < 41 && !use_old_passwords) + if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH && + !use_old_passwords) { sql_print_error("mysql.user table is not updated to new password format; " "Disabling new password usage until " @@ -516,6 +517,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) RETURN VALUE 0 success: thread data and mqh are updated 1 user not found or authentification 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. */ @@ -564,6 +566,9 @@ acl_getroot(THD *thd, USER_RESOURCES *mqh, else if (passwd_len == SCRAMBLE_LENGTH && user_i->salt_len == SCRAMBLE_LENGTH_323) res= -1; + else if (passwd_len == SCRAMBLE_LENGTH_323 && + user_i->salt_len == SCRAMBLE_LENGTH) + res= 2; /* linear search complete: */ break; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 384ec2bd4dd..a6d3121158c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -195,11 +195,8 @@ end: RETURN VALUE 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and thd->db_access are updated; OK is sent to client; - 1 access denied or internal error; error is sent to client - Note, that this return semantics differs from check_connection, - which returns -1 if message was already sent. - -1 acl entry for this user contains old scramble, but passwd contains - new one, error is not sent to client + -1 access denied or handshake error; error is sent to client; + >0 error, not sent to client */ static int check_user(THD *thd, enum enum_server_command command, @@ -208,87 +205,129 @@ static int check_user(THD *thd, enum enum_server_command command, { DBUG_ENTER("check_user"); + if (passwd_len != 0 && + passwd_len != SCRAMBLE_LENGTH && + passwd_len != SCRAMBLE_LENGTH_323) + DBUG_RETURN(ER_HANDSHAKE_ERROR); + /* Why this is set here? - probably to reset current DB to 'no database selected' in case of 'change user' failure. */ thd->db= 0; thd->db_length= 0; - + + char buff[NAME_LEN + 1]; /* to conditionally save db */ + USER_RESOURCES ur; int res= acl_getroot(thd, &ur, passwd, passwd_len, protocol_version == 9 || !(thd->client_capabilities & CLIENT_LONG_PASSWORD)); - if (res == 0 && !(thd->master_access & NO_ACCESS)) // authentification is OK + if (res == -1) { - DBUG_PRINT("info", - ("Capabilities: %d packet_length: %ld Host: '%s' " - "Login user: '%s' Priv_user: '%s' Using password: %s " - "Access: %u db: '%s'", - thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->user, thd->priv_user, - passwd_len ? "yes": "no", - thd->master_access, thd->db ? thd->db : "*none*")); - - if (check_count) + /* + This happens when client (new) sends password scrambled with + scramble(), but database holds old value (scrambled with + scramble_323()). Here we please client to send scrambled_password + in old format. + */ + /* save db because network buffer is to hold new packet */ + if (db) { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool count_ok= thread_count < max_connections + delayed_insert_threads || - thd->master_access & SUPER_ACL; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - if (!count_ok) - { // too many connections - send_error(thd, ER_CON_COUNT_ERROR); - DBUG_RETURN(1); - } + strmake(buff, db, NAME_LEN); + db= buff; + } + NET *net= &thd->net; + if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) || + net_flush(net) || + my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very + { // specific packet size + inc_host_errors(&thd->remote.sin_addr); + DBUG_RETURN(ER_HANDSHAKE_ERROR); } + /* Final attempt to check the user based on reply */ + /* So as passwd is short, errcode is always >= 0 */ + res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323, + false); + } + /* here res is always >= 0 */ + if (res == 0) + { + if (!(thd->master_access & NO_ACCESS)) // authentification is OK + { + DBUG_PRINT("info", + ("Capabilities: %d packet_length: %ld Host: '%s' " + "Login user: '%s' Priv_user: '%s' Using password: %s " + "Access: %u db: '%s'", + thd->client_capabilities, thd->max_client_packet_length, + thd->host_or_ip, thd->user, thd->priv_user, + passwd_len ? "yes": "no", + thd->master_access, thd->db ? thd->db : "*none*")); + + if (check_count) + { + VOID(pthread_mutex_lock(&LOCK_thread_count)); + bool count_ok= thread_count < max_connections + delayed_insert_threads + || thd->master_access & SUPER_ACL; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + if (!count_ok) + { // too many connections + send_error(thd, ER_CON_COUNT_ERROR); + DBUG_RETURN(-1); + } + } - /* Why logging is performed before all checks've passed? */ - mysql_log.write(thd,command, - (thd->priv_user == thd->user ? - (char*) "%s@%s on %s" : - (char*) "%s@%s as anonymous on %s"), - thd->user, thd->host_or_ip, - db ? db : (char*) ""); + /* Why logging is performed before all checks've passed? */ + mysql_log.write(thd,command, + (thd->priv_user == thd->user ? + (char*) "%s@%s on %s" : + (char*) "%s@%s as anonymous on %s"), + thd->user, thd->host_or_ip, + db ? db : (char*) ""); - /* Why is it set here? */ - thd->db_access=0; + /* Why is it set here? */ + thd->db_access=0; - /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || ur.connections) && - get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) - DBUG_RETURN(1); - if (thd->user_connect && thd->user_connect->user_resources.connections && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(1); + /* Don't allow user to connect if he has done too many queries */ + if ((ur.questions || ur.updates || ur.connections) && + get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) + DBUG_RETURN(1); + if (thd->user_connect && thd->user_connect->user_resources.connections && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(1); - /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ - if (db && db[0]) - { - if (mysql_change_db(thd, db)) + /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ + if (db && db[0]) { - if (thd->user_connect) - decrease_user_connections(thd->user_connect); - DBUG_RETURN(1); + if (mysql_change_db(thd, db)) + { + if (thd->user_connect) + decrease_user_connections(thd->user_connect); + DBUG_RETURN(-1); + } } + else + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages + /* Ready to handle queries */ + DBUG_RETURN(0); } - else - send_ok(thd); - thd->password= test(passwd_len); // remember for error messages - /* Ready to handle queries */ } - else if (res != -1) // authentication failure + else if (res == 2) // client gave short hash, server has long hash { - net_printf(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); - mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, - passwd_len ? ER(ER_YES) : ER(ER_NO)); + net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); + mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); } - DBUG_RETURN(res); + net_printf(thd, ER_ACCESS_DENIED_ERROR, + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), + thd->user, + thd->host_or_ip, + passwd_len ? ER(ER_YES) : ER(ER_NO)); + DBUG_RETURN(-1); } /* @@ -491,60 +530,6 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0) } -/* - Perform check for scrambled password, re-request scrambled password - from client if necessary. See also help for check_user. - SYNOPSIS - authenticate() - RETURN VALUE - 0 success, OK sent to client - -1 error, sent to client - > 0 error, not sent to client -*/ - -static -int -authenticate(THD *thd, enum enum_server_command command, - const char *passwd, uint passwd_len, const char *db, - bool check_count) -{ - if (passwd_len != 0 && - passwd_len != SCRAMBLE_LENGTH && - passwd_len != SCRAMBLE_LENGTH_323) - return 1; - int res= check_user(thd, COM_CONNECT, passwd, passwd_len, db, check_count); - if (res < 0) - { - /* - This happens when client (new) sends password scrambled with - scramble(), but database holds old value (scrambled with - scramble_323()). Here we please client to send scrambled_password - in old format. - */ - char buff[NAME_LEN + 1]; - /* save db because network buffer is to hold new packet */ - if (db) - { - strmake(buff, db, NAME_LEN); - db= buff; - } - NET *net= &thd->net; - if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) || - net_flush(net) || - my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very - { // specific packet size - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } - /* Final attempt to check the user based on reply */ - /* So as passwd is short, errcode is always sent to user and res >= 0 */ - res= check_user(thd, COM_CONNECT, (char *) net->read_pos, - SCRAMBLE_LENGTH_323, db, check_count); - } - return res > 0 ? -1 : 0; -} - - /* Perform handshake, authorize client and update thd ACL variables. SYNOPSIS @@ -643,7 +628,7 @@ check_connection(THD *thd) /* Old clients does not understand long scrambles, but can ignore packet - tail: that's why first part of scramble is placed here, and second + tail: that's why first part of the scramble is placed here, and second part at the end of packet. */ end= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1; @@ -760,17 +745,23 @@ check_connection(THD *thd) char *user= end; char *passwd= strend(user)+1; - uint passwd_len= strlen(passwd); - - char *db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? - passwd+passwd_len+1 : 0; + char *db= passwd; + /* + 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'. + */ + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? + db + passwd_len + 1 : 0; if (thd->user) x_free(thd->user); thd->user= my_strdup(user, MYF(0)); if (!thd->user) return(ER_OUT_OF_RESOURCES); - return authenticate(thd, COM_CONNECT, passwd, passwd_len, db, true); + return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true); } @@ -1137,8 +1128,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(com_other, &LOCK_status); char *user= (char*) packet; char *passwd= strend(user)+1; - uint passwd_len= strlen(passwd); - char *db= passwd + passwd_len + 1; + /* + Old clients send null-terminated string ('\0' for empty string) for + password. New clients send the size (1 byte) + string (not null + terminated, so also '\0' for empty string). + */ + char *db= passwd; + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? + *passwd++ : strlen(passwd); + db+= passwd_len + 1; /* Small check for incomming packet */ if ((uint) ((uchar*) db - net->read_pos) > packet_length) @@ -1163,7 +1161,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } - int res= authenticate(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); + int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); if (res) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c8c9eb97a6a..ddf4b71e891 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -493,6 +493,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MULTIPOINT %token MULTIPOLYGON %token NOW_SYM +%token OLD_PASSWORD %token PASSWORD %token POINTFROMTEXT %token POINT_SYM @@ -2516,9 +2517,11 @@ simple_expr: { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' { - $$= use_old_passwords ? (Item *) new Item_func_old_password($3) : - (Item *) new Item_func_password($3); - } + $$= use_old_passwords ? (Item *) new Item_func_old_password($3) : + (Item *) new Item_func_password($3); + } + | OLD_PASSWORD '(' expr ')' + { $$= new Item_func_old_password($3); } | POINT_SYM '(' expr ',' expr ')' { $$= new Item_func_point($3,$5); } | POINTFROMTEXT '(' expr ')' @@ -4412,6 +4415,7 @@ keyword: | NO_SYM {} | NONE_SYM {} | OFFSET_SYM {} + | OLD_PASSWORD {} | OPEN_SYM {} | PACK_KEYS_SYM {} | PARTIAL {} @@ -4603,24 +4607,15 @@ text_or_password: TEXT_STRING { $$=$1.str;} | PASSWORD '(' TEXT_STRING ')' { - if (!$3.length) - $$=$3.str; - else if (use_old_passwords) - { - char *buff= (char *) - YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); - if (buff) - make_scrambled_password_323(buff, $3.str); - $$=buff; - } - else - { - char *buff= (char *) - YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1); - if (buff) - make_scrambled_password(buff, $3.str); - $$=buff; - } + $$= $3.length ? use_old_passwords ? + Item_func_old_password::alloc(YYTHD, $3.str) : + Item_func_password::alloc(YYTHD, $3.str) : + $3.str; + } + | OLD_PASSWORD '(' TEXT_STRING ')' + { + $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) : + $3.str; } ; -- cgit v1.2.1 From 78c3d9684ce2e83efc00878c3e901487bd5267bf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Jul 2003 02:36:14 +0400 Subject: Preliminary support for options --secure-auth, --old-passwords Support for option --old-protocol was removed. Some test performed. Tests for SSL and replication are pending. More strict following to specification for --old-passwords is in the TODO. include/mysql_com.h: support for 3.20 passwords removed from scramble_323 include/mysqld_error.h: added error code for --secure-auth mode libmysql/libmysql.c: removed support for 3.20 password and protocol version 9 mysql-test/r/connect.result: added check for new syntax of set password mysql-test/r/func_crypt.result: tests for two-argument of password() were removed. Instead added tests for cooperation of password() and old_passwords session/global variable, passwords() and spaces in argument string mysql-test/t/connect.test: added check for new syntax of set password mysql-test/t/func_crypt.test: tests for two-argument of password() were removed. Instead added tests for cooperation of password() and old_passwords session/global variable, passwords() and spaces in argument string sql-common/client.c: removed support for 3.20 servers and protocol version 9 sql/item_strfunc.h: fixed comment sql/mysql_priv.h: added declarartion for option opt_secure_auth sql/mysqld.cc: added option opt_secure_auth option old-password placed according to sort order sql/password.c: removed support for 3.20 clients and old scrambles sql/set_var.cc: added system variable 'secure_auth' added system/thread variable 'old_passwords' sql/set_var.h: sys_old_passwords needs to be exported because sys_old_passwords.after_update is used in sql_acl.cc sql/sql_acl.cc: support for 3.20 passwords removed now acl_init honors options works properly with options/variables --secure-auth and --old-passwords sql/sql_acl.h: support for 3.20 clients removed sql/sql_class.h: added system/thread variable old_passwords sql/sql_parse.cc: support for 3.20 clients removed now check_user takes into account option secure_auth sql/sql_yacc.yy: global variable use_old_passwords replaced with thread-specific variable old_passwords sql/share/czech/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/danish/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/dutch/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/english/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/estonian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/french/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/german/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/greek/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/hungarian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/italian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/japanese/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/korean/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/norwegian-ny/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/norwegian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/polish/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/portuguese/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/romanian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/russian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/serbian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/slovak/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/spanish/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/swedish/errmsg.txt: error message for --secure-auth added (as suggested by Paul) sql/share/ukrainian/errmsg.txt: error message for --secure-auth added (as suggested by Paul) --- include/mysql_com.h | 5 +-- include/mysqld_error.h | 3 +- libmysql/libmysql.c | 6 +-- mysql-test/r/connect.result | 1 + mysql-test/r/func_crypt.result | 88 +++++++++++++++++++++++++++++++++------ mysql-test/t/connect.test | 5 ++- mysql-test/t/func_crypt.test | 34 +++++++++++++-- sql-common/client.c | 6 +-- sql/item_strfunc.h | 2 +- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 25 ++++++----- sql/password.c | 55 +++++------------------- sql/set_var.cc | 6 +++ sql/set_var.h | 2 + sql/share/czech/errmsg.txt | 1 + sql/share/danish/errmsg.txt | 1 + sql/share/dutch/errmsg.txt | 1 + sql/share/english/errmsg.txt | 1 + sql/share/estonian/errmsg.txt | 1 + sql/share/french/errmsg.txt | 1 + sql/share/german/errmsg.txt | 1 + sql/share/greek/errmsg.txt | 1 + sql/share/hungarian/errmsg.txt | 1 + sql/share/italian/errmsg.txt | 1 + sql/share/japanese/errmsg.txt | 1 + sql/share/korean/errmsg.txt | 1 + sql/share/norwegian-ny/errmsg.txt | 1 + sql/share/norwegian/errmsg.txt | 1 + sql/share/polish/errmsg.txt | 1 + sql/share/portuguese/errmsg.txt | 1 + sql/share/romanian/errmsg.txt | 1 + sql/share/russian/errmsg.txt | 1 + sql/share/serbian/errmsg.txt | 1 + sql/share/slovak/errmsg.txt | 1 + sql/share/spanish/errmsg.txt | 1 + sql/share/swedish/errmsg.txt | 1 + sql/share/ukrainian/errmsg.txt | 1 + sql/sql_acl.cc | 82 +++++++++++++++++++++++------------- sql/sql_acl.h | 4 +- sql/sql_class.h | 1 + sql/sql_parse.cc | 32 +++++++++++--- sql/sql_yacc.yy | 7 ++-- 42 files changed, 264 insertions(+), 125 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 784a7782855..1f9d996c457 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -319,10 +319,9 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st); void hash_password(ulong *to, const char *password); void make_scrambled_password_323(char *to, const char *password); -char *scramble_323(char *to, const char *message, const char *password, - my_bool old_ver); +char *scramble_323(char *to, const char *message, const char *password); my_bool check_scramble_323(const char *, const char *message, - unsigned long *salt, my_bool old_ver); + unsigned long *salt); void get_salt_from_password_323(unsigned long *res, const char *password); void make_password_from_salt_323(char *to, const unsigned long *salt); diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 565c2812c50..341e0144ca3 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -286,4 +286,5 @@ #define ER_REVOKE_GRANTS 1267 #define ER_CANT_AGGREGATE_3COLLATIONS 1268 #define ER_CANT_AGGREGATE_NCOLLATIONS 1269 -#define ER_ERROR_MESSAGES 270 +#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1270 +#define ER_ERROR_MESSAGES 271 diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 8b83343df8f..1cf4880db24 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -626,8 +626,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, end+= SCRAMBLE_LENGTH; } else - end= scramble_323(end, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)) + 1; + end= scramble_323(end, mysql->scramble_323, passwd); } else *end++= '\0'; // empty password @@ -651,8 +650,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, By sending this very specific reply server asks us to send scrambled password in old format. The reply contains scramble_323. */ - scramble_323(buff, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)); + scramble_323(buff, mysql->scramble_323, passwd); if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) { net->last_errno= CR_SERVER_LOST; diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index 9c848c3434f..c0608af0de2 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -30,6 +30,7 @@ show tables; Tables_in_test update mysql.user set password=old_password("gambling2") where user="test"; flush privileges; +set password=old_password('gambling3'); show tables; Tables_in_mysql columns_priv diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index 461ae1e7e09..bd4c6d41d39 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -1,15 +1,79 @@ select length(encrypt('foo', 'ff')) <> 0; length(encrypt('foo', 'ff')) <> 0 1 -select password("a",""), password("a",NULL), password("","a"), password(NULL,"a"); -password("a","") password("a",NULL) password("","a") password(NULL,"a") -*2517f7235d68d4ba2e5019c93420523101157a792c01 NULL NULL -select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa"); -password("aaaaaaaaaaaaaaaa","a") password("a","aaaaaaaaaaaaaaaa") -*2cd3b9a44e9a9994789a30f935c92f45a96c5472f381 *37c7c5c794ff144819f2531bf03c57772cd84e40db09 -select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa'); -old_password('test') length(password("1")) length(encrypt('test')) encrypt('test','aa') -378b243e220ca493 45 13 aaqPiZY5xR5l. -select old_password(""), old_password(NULL), password(""), password(NULL); -old_password("") old_password(NULL) password("") password(NULL) - NULL NULL +select password('abc'); +password('abc') +*0d3ced9bec10a777aec23ccc353a8c08a633045e +select password(''); +password('') + +select old_password('abc'); +old_password('abc') +7cd2b5942be28759 +select old_password(''); +old_password('') + +select password('gabbagabbahey'); +password('gabbagabbahey') +*b0f99d2963660dd7e16b751ec9ee2f17b6a68fa6 +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +select length(password('1')); +length(password('1')) +41 +select length(encrypt('test')); +length(encrypt('test')) +13 +select encrypt('test','aa'); +encrypt('test','aa') +aaqPiZY5xR5l. +select old_password(NULL); +old_password(NULL) +NULL +select password(NULL); +password(NULL) +NULL +set global old_passwords=on; +select password(''); +password('') + +select old_password(''); +old_password('') + +select password('idkfa'); +password('idkfa') +*b669c9dac3aa6f2254b03cdef8dfdd6b2d1054ba +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set old_passwords=on; +select password('idkfa'); +password('idkfa') +5c078dc54ca0fcca +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set global old_passwords=off; +select password('idkfa'); +password('idkfa') +5c078dc54ca0fcca +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +set old_passwords=off; +select password('idkfa '); +password('idkfa ') +*2dc31d90647b4c1abc9231563d2236e96c9a2db2 +select password('idkfa'); +password('idkfa') +*b669c9dac3aa6f2254b03cdef8dfdd6b2d1054ba +select password(' idkfa'); +password(' idkfa') +*12b099e56bb7fe8d43c78fd834a9d1d11178d045 +select old_password('idkfa'); +old_password('idkfa') +5c078dc54ca0fcca +select old_password(' i d k f a '); +old_password(' i d k f a ') +5c078dc54ca0fcca diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index e6ccc52f0d4..7585ff0f608 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -48,8 +48,9 @@ flush privileges; #connect (con1,localhost,test,gambling2,""); #show tables; connect (con1,localhost,test,gambling2,mysql); +set password=old_password('gambling3'); show tables; -connect (con1,localhost,test,gambling2,test); +connect (con1,localhost,test,gambling3,test); show tables; # Re enable this one day if error handling on connect will take place @@ -63,7 +64,9 @@ show tables; #connect (con1,localhost,test,zorro,); #--error 1045 + # remove user 'test' so that other tests which may use 'test' # do not depend on this test. + delete from mysql.user where user="test"; flush privileges; diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index c72356bda1a..c1c7090cab3 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -4,7 +4,33 @@ select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. # Test new and old password handling functions -select password("a",""), password("a",NULL), password("","a"), password(NULL,"a"); -select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa"); -select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa'); -select old_password(""), old_password(NULL), password(""), password(NULL); +select password('abc'); +select password(''); +select old_password('abc'); +select old_password(''); +select password('gabbagabbahey'); +select old_password('idkfa'); +select length(password('1')); +select length(encrypt('test')); +select encrypt('test','aa'); +select old_password(NULL); +select password(NULL); +set global old_passwords=on; +select password(''); +select old_password(''); +select password('idkfa'); +select old_password('idkfa'); +set old_passwords=on; +select password('idkfa'); +select old_password('idkfa'); +set global old_passwords=off; +select password('idkfa'); +select old_password('idkfa'); + +# this test shows that new scrambles honor spaces in passwords: +set old_passwords=off; +select password('idkfa '); +select password('idkfa'); +select password(' idkfa'); +select old_password('idkfa'); +select old_password(' i d k f a '); diff --git a/sql-common/client.c b/sql-common/client.c index efb71021f8d..9a0b7eb3fe2 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1842,8 +1842,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, end+= SCRAMBLE_LENGTH; } else - end= scramble_323(end, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)) + 1; + end= scramble_323(end, mysql->scramble_323, passwd) + 1; } else *end++= '\0'; /* empty password */ @@ -1880,8 +1879,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, By sending this very specific reply server asks us to send scrambled password in old format. The reply contains scramble_323. */ - scramble_323(buff, mysql->scramble_323, passwd, - (my_bool) (mysql->protocol_version == 9)); + scramble_323(buff, mysql->scramble_323, passwd); if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) { net->last_errno= CR_SERVER_LOST; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 3e0239cf76a..96e264fd8d2 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -277,7 +277,7 @@ public: /* Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0 compatibility mode. This item is created in sql_yacc.yy when - 'use_old_passwords' session variable is set, and to handle OLD_PASSWORD() + 'old_passwords' session variable is set, and to handle OLD_PASSWORD() function. */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 13ff168e553..f8bf197249b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -748,7 +748,7 @@ extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern my_bool opt_readonly; extern my_bool opt_enable_named_pipe; -extern my_bool opt_old_passwords, use_old_passwords; +extern my_bool opt_secure_auth; extern char *shared_memory_base_name, *mysqld_unix_port; extern bool opt_enable_shared_memory; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2677973ff0e..c5f875bfcc8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -250,9 +250,10 @@ my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool lower_case_table_names, opt_old_rpl_compat; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; -my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0; +my_bool opt_log_slave_updates= 0; my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam; my_bool opt_readonly, use_temp_pool, relay_log_purge; +my_bool opt_secure_auth= 0; volatile bool mqh_used = 0; uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; @@ -3452,7 +3453,8 @@ enum options OPT_EXPIRE_LOGS_DAYS, OPT_DEFAULT_WEEK_FORMAT, OPT_GROUP_CONCAT_MAX_LEN, - OPT_DEFAULT_COLLATION + OPT_DEFAULT_COLLATION, + OPT_SECURE_AUTH }; @@ -3753,9 +3755,10 @@ Does nothing yet.", (gptr*) &opt_no_mix_types, (gptr*) &opt_no_mix_types, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"old-protocol", 'o', "Use the old (3.20) protocol client/server protocol.", - (gptr*) &protocol_version, (gptr*) &protocol_version, 0, GET_UINT, NO_ARG, - PROTOCOL_VERSION, 0, 0, 0, 0, 0}, + {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).", + (gptr*) &global_system_variables.old_passwords, + (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"old-rpl-compat", OPT_OLD_RPL_COMPAT, "Use old LOAD DATA format in the binary log (don't save data in file).", (gptr*) &opt_old_rpl_compat, (gptr*) &opt_old_rpl_compat, 0, GET_BOOL, @@ -3824,8 +3827,6 @@ relay logs.", GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).", - (gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_DELETED {"safe-show-database", OPT_SAFE_SHOW_DB, "Deprecated option; One should use GRANT SHOW DATABASES instead...", @@ -3835,6 +3836,9 @@ relay logs.", "Don't allow new user creation by the user who has no write privileges to the mysql.user table.", (gptr*) &opt_safe_user_create, (gptr*) &opt_safe_user_create, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.", + (gptr*) &opt_secure_auth, (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG, + my_bool(0), 0, 0, 0, 0, 0}, {"server-id", OPT_SERVER_ID, "Uniquely identifies the server instance in the community of replication partners.", (gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, @@ -4604,7 +4608,8 @@ static void mysql_init_variables(void) opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0; opt_disable_networking= opt_skip_show_db=0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0; - opt_bootstrap= opt_myisam_log= use_old_passwords= 0; + opt_secure_auth= 0; + opt_bootstrap= opt_myisam_log= 0; mqh_used= 0; segfaulted= kill_in_progress= 0; cleanup_done= 0; @@ -4704,6 +4709,7 @@ static void mysql_init_variables(void) max_system_variables.select_limit= (ulonglong) HA_POS_ERROR; global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + global_system_variables.old_passwords= 0; /* Variables that depends on compile options */ #ifndef DBUG_OFF @@ -4825,9 +4831,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'L': strmake(language, argument, sizeof(language)-1); break; - case 'o': - protocol_version=PROTOCOL_VERSION-1; - break; #ifdef HAVE_REPLICATION case OPT_SLAVE_SKIP_ERRORS: init_slave_skip_errors(argument); diff --git a/sql/password.c b/sql/password.c index bfdb453af01..2e9139c12aa 100644 --- a/sql/password.c +++ b/sql/password.c @@ -88,24 +88,6 @@ void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) } -/* - Old (MySQL 3.20) random generation structure initialization - XXX: is to be deleted very soon! - SYNOPSIS - old_randominit() - rand_st OUT Structure to initialize - seed1 IN First initialization parameter -*/ - -static void old_randominit(struct rand_struct *rand_st, ulong seed1) -{ /* For mysql 3.20.# */ - rand_st->max_value= 0x01FFFFFFL; - rand_st->max_value_dbl=(double) rand_st->max_value; - seed1%=rand_st->max_value; - rand_st->seed1=seed1 ; rand_st->seed2=seed1/2; -} - - /* Generate random number. SYNOPSIS @@ -178,13 +160,11 @@ void make_scrambled_password_323(char *to, const char *password) message IN Message to scramble. Message must be exactly SRAMBLE_LENGTH_323 long and NULL terminated. password IN Password to use while scrambling - old_ver IN Force old version random number generator RETURN End of scrambled string */ -char *scramble_323(char *to, const char *message, const char *password, - my_bool old_ver) +char *scramble_323(char *to, const char *message, const char *password) { struct rand_struct rand_st; ulong hash_pass[2], hash_message[2]; @@ -194,21 +174,15 @@ char *scramble_323(char *to, const char *message, const char *password, char *to_start=to; hash_password(hash_pass,password); hash_password(hash_message, message); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); while (*message++) *to++= (char) (floor(my_rnd(&rand_st)*31)+64); - if (!old_ver) - { /* Make it harder to break */ - char extra=(char) (floor(my_rnd(&rand_st)*31)); - while (to_start != to) - *(to_start++)^=extra; - } + char extra=(char) (floor(my_rnd(&rand_st)*31)); + while (to_start != to) + *(to_start++)^=extra; } - *to=0; + *to= 0; return to; } @@ -223,7 +197,6 @@ char *scramble_323(char *to, const char *message, const char *password, be exactly SCRAMBLED_LENGTH_323 bytes long and NULL-terminated. hash_pass IN password which should be used for scrambling - old_ver IN force old (3.20) version random number generator RETURN VALUE 0 - password correct !0 - password invalid @@ -231,7 +204,7 @@ char *scramble_323(char *to, const char *message, const char *password, my_bool check_scramble_323(const char *scrambled, const char *message, - ulong *hash_pass, my_bool old_ver) + ulong *hash_pass) { struct rand_struct rand_st; ulong hash_message[2]; @@ -243,18 +216,12 @@ check_scramble_323(const char *scrambled, const char *message, return 1; /* Wrong password */ hash_password(hash_message,message); - if (old_ver) - old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]); - else - randominit(&rand_st,hash_pass[0] ^ hash_message[0], - hash_pass[1] ^ hash_message[1]); + randominit(&rand_st,hash_pass[0] ^ hash_message[0], + hash_pass[1] ^ hash_message[1]); to=buff; for (pos=scrambled ; *pos ; pos++) *to++=(char) (floor(my_rnd(&rand_st)*31)+64); - if (old_ver) - extra=0; - else - extra=(char) (floor(my_rnd(&rand_st)*31)); + extra=(char) (floor(my_rnd(&rand_st)*31)); to=buff; while (*scrambled) { diff --git a/sql/set_var.cc b/sql/set_var.cc index a281fac530a..a4ecf24d09f 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -210,6 +210,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", &SV::net_retry_count, fix_net_retry_count); sys_var_thd_bool sys_new_mode("new", &SV::new_mode); +sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords); sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size", &SV::preload_buff_size); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", @@ -236,6 +237,7 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type", &SV::query_cache_type, &query_cache_type_typelib); #endif /* HAVE_QUERY_CACHE */ +sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth); sys_var_long_ptr sys_server_id("server_id",&server_id); sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", &opt_slave_compressed_protocol); @@ -425,6 +427,7 @@ sys_var *sys_variables[]= &sys_net_wait_timeout, &sys_net_write_timeout, &sys_new_mode, + &sys_old_passwords, &sys_preload_buff_size, &sys_pseudo_thread_id, &sys_query_cache_size, @@ -443,6 +446,7 @@ sys_var *sys_variables[]= #endif &sys_rpl_recovery_rank, &sys_safe_updates, + &sys_secure_auth, &sys_select_limit, &sys_server_id, #ifdef HAVE_REPLICATION @@ -600,6 +604,7 @@ struct show_var_st init_vars[]= { {sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS}, {sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS}, {sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS}, + {sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS}, {"open_files_limit", (char*) &open_files_limit, SHOW_LONG}, {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"log_error", (char*) log_error_file, SHOW_CHAR}, @@ -620,6 +625,7 @@ struct show_var_st init_vars[]= { SHOW_SYS}, {sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS}, {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, + {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ #ifdef HAVE_SMEM {"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL}, diff --git a/sql/set_var.h b/sql/set_var.h index 5a0fbd21809..0622e504499 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -652,3 +652,5 @@ ulong fix_sql_mode(ulong sql_mode); extern sys_var_str sys_charset_system; CHARSET_INFO *get_old_charset_by_name(const char *old_name); + +extern sys_var_thd_bool sys_old_passwords; diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 641b1384e9a..4f1836ef80a 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -275,3 +275,4 @@ v/* "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 574d26b7c1c..138c8c59a39 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -269,3 +269,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index c6c975cb141..f7a79dfa738 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -277,3 +277,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index f39c415fa55..c57527e2578 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index de22d6fd111..e6ade1c7e3d 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 6c1187cd0e4..7ffd834fbcf 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 78d53034a71..2c6343eeeea 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -275,3 +275,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 347370f1ac8..228834f7937 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 313275b3cb6..620234e2321 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8af7e3ba9f7..8091d3185ba 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 417a03978fb..962505423b1 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 22395d0fb6a..aa0439fcd32 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index de6db62cdce..21dfad648b9 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 28db8caa8bc..e1d7501bca4 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index fdf856c7e56..eaa2395b675 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -270,3 +270,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 397784dc7dd..89aded8afce 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8f1cdb7b259..e76fd43e841 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -270,3 +270,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index ec41a6acb34..23d20c1b8fe 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 77d35be2fc9..e0ba1413f5e 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -262,3 +262,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 33cabdfc752..bc8949127fd 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -274,3 +274,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 35e26f35ff7..9a6dcd90a4d 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -267,3 +267,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 9cdcb20db35..3538ba3c47e 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 5a614714de2..9bc07241856 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index f88799c2843..ee544335a99 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -87,16 +87,33 @@ set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) get_salt_from_password(acl_user->salt, password); acl_user->salt_len= SCRAMBLE_LENGTH; } - else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 - || password_len == 8 && protocol_version == 9) + else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { get_salt_from_password_323((ulong *) acl_user->salt, password); - acl_user->salt_len= password_len/2; + acl_user->salt_len= SCRAMBLE_LENGTH_323; } else acl_user->salt_len= 0; } +/* + This after_update function is used when user.password is less than + SCRAMBLE_LENGTH bytes. +*/ + +static void restrict_update_of_old_passwords_var(THD *thd, + enum_var_type var_type) +{ + if (var_type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.old_passwords= 1; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.old_passwords= 1; +} + /* Read grant privileges from the privilege tables in the 'mysql' database. @@ -139,8 +156,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (!(thd=new THD)) DBUG_RETURN(1); /* purecov: inspected */ thd->store_globals(); - /* Use passwords according to command line option */ - use_old_passwords= opt_old_passwords; acl_cache->clear(1); // Clear locked hostname cache thd->db= my_strdup("mysql",MYF(0)); @@ -197,24 +212,43 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); - if (table->field[2]->field_length == 8 && - protocol_version == PROTOCOL_VERSION) + if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323) { - sql_print_error("Old 'user' table. " - "(Check README or the Reference manual). " - "Continuing --old-protocol"); /* purecov: tested */ - protocol_version=9; /* purecov: tested */ + sql_print_error("Fatal error: mysql.user table is damaged or in " + "unsupported 3.20 format."); + goto end; } DBUG_PRINT("info",("user table fields: %d, password length: %d", table->fields, table->field[2]->field_length)); - if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH && - !use_old_passwords) + + pthread_mutex_lock(&LOCK_global_system_variables); + if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) { - sql_print_error("mysql.user table is not updated to new password format; " - "Disabling new password usage until " - "mysql_fix_privilege_tables is run"); - use_old_passwords= 1; + if (opt_secure_auth) + { + pthread_mutex_unlock(&LOCK_global_system_variables); + sql_print_error("Fatal error: mysql.user table is in old format, " + "but server started with --secure-auth option."); + goto end; + } + sys_old_passwords.after_update= restrict_update_of_old_passwords_var; + if (global_system_variables.old_passwords) + pthread_mutex_unlock(&LOCK_global_system_variables); + else + { + global_system_variables.old_passwords= 1; + pthread_mutex_unlock(&LOCK_global_system_variables); + sql_print_error("mysql.user table is not updated to new password format; " + "Disabling new password usage until " + "mysql_fix_privilege_tables is run"); + } + thd->variables.old_passwords= 1; + } + else + { + sys_old_passwords.after_update= 0; + pthread_mutex_unlock(&LOCK_global_system_variables); } allow_all_hosts=0; @@ -229,12 +263,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (user.salt_len == 0 && password_len != 0) { switch (password_len) { - case 8: /* 3.20: to be removed */ - sql_print_error("Found old style password for user '%s'. " - "Ignoring user. (You may want to restart mysqld " - "using --old-protocol) ", - user.user ? user.user : ""); - break; case 45: /* 4.1: to be removed */ sql_print_error("Found 4.1 style password for user '%s'. " "Ignoring user. " @@ -513,7 +541,6 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) original random string, passwd_len IN length of passwd, must be one of 0, 8, SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH - old_version IN if old (3.20) protocol is used RETURN VALUE 0 success: thread data and mqh are updated 1 user not found or authentification failure @@ -521,9 +548,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) -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, bool old_version) +int acl_getroot(THD *thd, USER_RESOURCES *mqh, + const char *passwd, uint passwd_len) { DBUG_ENTER("acl_getroot"); @@ -557,7 +583,7 @@ acl_getroot(THD *thd, USER_RESOURCES *mqh, user_i->salt_len == SCRAMBLE_LENGTH && check_scramble(passwd, thd->scramble, user_i->salt) == 0 || check_scramble_323(passwd, thd->scramble_323, - (ulong *) user_i->salt, old_version) == 0) + (ulong *) user_i->salt) == 0) { acl_user= user_i; res= 0; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 3370797820a..b4ee1a9b15f 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -135,8 +135,8 @@ void acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db); -int acl_getroot(THD *thd, USER_RESOURCES *mqh, - const char *passwd, uint passwd_len, bool old_ver); +int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, + uint passwd_len); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, const char *host, const char *user); bool change_password(THD *thd, const char *host, const char *user, diff --git a/sql/sql_class.h b/sql/sql_class.h index d962cc8086e..5e46f44634b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -386,6 +386,7 @@ struct system_variables my_bool log_warnings; my_bool low_priority_updates; my_bool new_mode; + my_bool old_passwords; CHARSET_INFO *character_set_server; CHARSET_INFO *character_set_database; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a6d3121158c..4b7486c7b4f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -204,7 +204,22 @@ static int check_user(THD *thd, enum enum_server_command command, bool check_count) { DBUG_ENTER("check_user"); - + + my_bool opt_secure_auth_local; + pthread_mutex_lock(&LOCK_global_system_variables); + opt_secure_auth_local= opt_secure_auth; + pthread_mutex_unlock(&LOCK_global_system_variables); + + /* + If the server is running in secure auth mode, short scrambles are + forbidden. + */ + if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323) + { + net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE); + mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE)); + DBUG_RETURN(-1); + } if (passwd_len != 0 && passwd_len != SCRAMBLE_LENGTH && passwd_len != SCRAMBLE_LENGTH_323) @@ -220,9 +235,7 @@ static int check_user(THD *thd, enum enum_server_command command, char buff[NAME_LEN + 1]; /* to conditionally save db */ USER_RESOURCES ur; - int res= acl_getroot(thd, &ur, passwd, passwd_len, - protocol_version == 9 || - !(thd->client_capabilities & CLIENT_LONG_PASSWORD)); + int res= acl_getroot(thd, &ur, passwd, passwd_len); if (res == -1) { /* @@ -231,6 +244,14 @@ static int check_user(THD *thd, enum enum_server_command command, scramble_323()). Here we please client to send scrambled_password in old format. */ + if (opt_secure_auth_local) + { + net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, + thd->user, thd->host_or_ip); + mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), + thd->user, thd->host_or_ip); + DBUG_RETURN(-1); + } /* save db because network buffer is to hold new packet */ if (db) { @@ -247,8 +268,7 @@ static int check_user(THD *thd, enum enum_server_command command, } /* Final attempt to check the user based on reply */ /* So as passwd is short, errcode is always >= 0 */ - res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323, - false); + res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323); } /* here res is always >= 0 */ if (res == 0) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ddf4b71e891..e283991b496 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2517,7 +2517,8 @@ simple_expr: { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' { - $$= use_old_passwords ? (Item *) new Item_func_old_password($3) : + $$= YYTHD->variables.old_passwords ? + (Item *) new Item_func_old_password($3) : (Item *) new Item_func_password($3); } | OLD_PASSWORD '(' expr ')' @@ -4607,7 +4608,7 @@ text_or_password: TEXT_STRING { $$=$1.str;} | PASSWORD '(' TEXT_STRING ')' { - $$= $3.length ? use_old_passwords ? + $$= $3.length ? YYTHD->variables.old_passwords ? Item_func_old_password::alloc(YYTHD, $3.str) : Item_func_password::alloc(YYTHD, $3.str) : $3.str; @@ -4923,7 +4924,7 @@ grant_user: $$=$1; $1->password=$4; if ($4.length) { - if (use_old_passwords) + if (YYTHD->variables.old_passwords) { char *buff= (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); -- cgit v1.2.1 From 30ced7f7f61aa25b486ab2134b1fa81310647bc6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Jul 2003 18:25:54 +0400 Subject: Style fixes, comments for 4.1.1 authorization Now special 1-byte packet is used for request of old password Fixed bug with --skip-grant-tables and acl_getroot include/mysql.h: removed scramble_323 member as now scramble_323 function does not count on trailing zero for scramble include/mysql_com.h: updated declarations libmysql/libmysql.c: now server sends special 1-byte packet instead of old scramble to re-request password. mysql->scramble_323 replaced with mysql->scramble sql-common/client.c: now server sends special 1-byte packet instead of old scramble to re-request password. mysql->scramble_323 replaces with mysql->scramble sql/password.c: comments beautified hash_password now accepts password length sql/protocol.cc: added send_old_password_request function sql/protocol.h: added send_old_password_request function sql/sql_acl.cc: style fixes, bug with --skip-grant-tables and acl_getroot fixed sql/sql_class.h: thd->scramble_323 removed as now old functions accept not null-terminated scrambles sql/sql_crypt.cc: fixed with new hash_password proto sql/sql_parse.cc: style fixes few comments added --- include/mysql.h | 4 +-- include/mysql_com.h | 4 +-- libmysql/libmysql.c | 10 +++--- sql-common/client.c | 13 ++++---- sql/password.c | 93 ++++++++++++++++++++++++++--------------------------- sql/protocol.cc | 19 +++++++++++ sql/protocol.h | 1 + sql/sql_acl.cc | 54 +++++++++++++++++++------------ sql/sql_class.h | 8 +---- sql/sql_crypt.cc | 2 +- sql/sql_parse.cc | 56 +++++++++++++++++--------------- 11 files changed, 148 insertions(+), 116 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index bf05f6e8e37..079808d9ba7 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -228,8 +228,8 @@ typedef struct st_mysql my_bool free_me; /* If free in mysql_close */ my_bool reconnect; /* set to 1 if automatic reconnect */ - char scramble[SCRAMBLE_LENGTH+1]; /* for new servers */ - char scramble_323[SCRAMBLE_LENGTH_323+1]; /* for old servers */ + /* session-wide random string */ + char scramble[max(SCRAMBLE_LENGTH,SCRAMBLE_LENGTH_323)+1]; /* Set if this is the original connection, not a master or a slave we have diff --git a/include/mysql_com.h b/include/mysql_com.h index e5782235934..87cedafb93d 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -318,9 +318,9 @@ void randominit(struct rand_struct *, unsigned long seed1, double my_rnd(struct rand_struct *); void create_random_string(char *to, uint length, struct rand_struct *rand_st); -void hash_password(ulong *to, const char *password); +void hash_password(ulong *to, const char *password, uint password_len); void make_scrambled_password_323(char *to, const char *password); -char *scramble_323(char *to, const char *message, const char *password); +void scramble_323(char *to, const char *message, const char *password); my_bool check_scramble_323(const char *, const char *message, unsigned long *salt); void get_salt_from_password_323(unsigned long *res, const char *password); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index ee7fd6a2576..cec9980bae7 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -626,7 +626,10 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, end+= SCRAMBLE_LENGTH; } else - end= scramble_323(end, mysql->scramble_323, passwd); + { + scramble_323(end, mysql->scramble, passwd); + end+= SCRAMBLE_LENGTH_323 + 1; + } } else *end++= '\0'; // empty password @@ -642,15 +645,14 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, if (pkt_length == packet_error) goto error; - if (net->read_pos[0] == mysql->scramble_323[0] && - pkt_length == SCRAMBLE_LENGTH_323 + 1 && + if (pkt_length == 1 && net->read_pos[0] == 254 && mysql->server_capabilities & CLIENT_SECURE_CONNECTION) { /* By sending this very specific reply server asks us to send scrambled password in old format. The reply contains scramble_323. */ - scramble_323(buff, mysql->scramble_323, passwd); + scramble_323(buff, mysql->scramble, passwd); if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) { net->last_errno= CR_SERVER_LOST; diff --git a/sql-common/client.c b/sql-common/client.c index 9a0b7eb3fe2..aac5be4b690 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1641,9 +1641,8 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, Scramble is split into two parts because old clients does not understand long scrambles; here goes the first part. */ - strmake(mysql->scramble_323, end, SCRAMBLE_LENGTH_323); + strmake(mysql->scramble, end, SCRAMBLE_LENGTH_323); end+= SCRAMBLE_LENGTH_323+1; - memcpy(mysql->scramble, mysql->scramble_323, SCRAMBLE_LENGTH_323); if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) mysql->server_capabilities=uint2korr(end); @@ -1842,7 +1841,10 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, end+= SCRAMBLE_LENGTH; } else - end= scramble_323(end, mysql->scramble_323, passwd) + 1; + { + scramble_323(end, mysql->scramble, passwd); + end+= SCRAMBLE_LENGTH_323 + 1; + } } else *end++= '\0'; /* empty password */ @@ -1871,15 +1873,14 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, if ((pkt_length=net_safe_read(mysql)) == packet_error) goto error; - if (net->read_pos[0] == mysql->scramble_323[0] && - pkt_length == SCRAMBLE_LENGTH_323 + 1 && + if (pkt_length == 1 && net->read_pos[0] == 254 && mysql->server_capabilities & CLIENT_SECURE_CONNECTION) { /* By sending this very specific reply server asks us to send scrambled password in old format. The reply contains scramble_323. */ - scramble_323(buff, mysql->scramble_323, passwd); + scramble_323(buff, mysql->scramble, passwd); if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) { net->last_errno= CR_SERVER_LOST; diff --git a/sql/password.c b/sql/password.c index 2e9139c12aa..16227aab611 100644 --- a/sql/password.c +++ b/sql/password.c @@ -110,15 +110,17 @@ double my_rnd(struct rand_struct *rand_st) Used for Pre-4.1 password handling SYNOPSIS hash_password() - result OUT store hash in this location - password IN plain text password to build hash + result OUT store hash in this location + password IN plain text password to build hash + password_len IN password length (password may be not null-terminated) */ -void hash_password(ulong *result, const char *password) +void hash_password(ulong *result, const char *password, uint password_len) { register ulong nr=1345345333L, add=7, nr2=0x12345671L; ulong tmp; - for (; *password ; password++) + const char *password_end= password + password_len; + for (; password < password_end; password++) { if (*password == ' ' || *password == '\t') continue; /* skip space in password */ @@ -129,7 +131,6 @@ void hash_password(ulong *result, const char *password) } result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */; result[1]=nr2 & (((ulong) 1L << 31) -1L); - return; } @@ -145,7 +146,7 @@ void hash_password(ulong *result, const char *password) void make_scrambled_password_323(char *to, const char *password) { ulong hash_res[2]; - hash_password(hash_res, password); + hash_password(hash_res, password, strlen(password)); sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]); } @@ -157,14 +158,12 @@ void make_scrambled_password_323(char *to, const char *password) scramble_323() to OUT Store scrambled message here. Buffer must be at least SCRAMBLE_LENGTH_323+1 bytes long - message IN Message to scramble. Message must be exactly - SRAMBLE_LENGTH_323 long and NULL terminated. + message IN Message to scramble. Message must be at least + SRAMBLE_LENGTH_323 bytes long. password IN Password to use while scrambling - RETURN - End of scrambled string */ -char *scramble_323(char *to, const char *message, const char *password) +void scramble_323(char *to, const char *message, const char *password) { struct rand_struct rand_st; ulong hash_pass[2], hash_message[2]; @@ -172,18 +171,18 @@ char *scramble_323(char *to, const char *message, const char *password) if (password && password[0]) { char *to_start=to; - hash_password(hash_pass,password); - hash_password(hash_message, message); + hash_password(hash_pass,password, strlen(password)); + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); - while (*message++) + const char *message_end= message + SCRAMBLE_LENGTH_323; + for (; message < message_end; message++) *to++= (char) (floor(my_rnd(&rand_st)*31)+64); char extra=(char) (floor(my_rnd(&rand_st)*31)); while (to_start != to) *(to_start++)^=extra; } *to= 0; - return to; } @@ -192,11 +191,13 @@ char *scramble_323(char *to, const char *message, const char *password) Used in pre 4.1 password handling SYNOPSIS check_scramble_323() - scrambled IN scrambled message to check. - message IN original random message which was used for scrambling; must - be exactly SCRAMBLED_LENGTH_323 bytes long and - NULL-terminated. - hash_pass IN password which should be used for scrambling + scrambled scrambled message to check. + message original random message which was used for scrambling; must + be exactly SCRAMBLED_LENGTH_323 bytes long and + NULL-terminated. + hash_pass password which should be used for scrambling + All params are IN. + RETURN VALUE 0 - password correct !0 - password invalid @@ -211,11 +212,7 @@ check_scramble_323(const char *scrambled, const char *message, char buff[16],*to,extra; /* Big enough for check */ const char *pos; - /* Check if this exactly N bytes. Overwise this is something fishy */ - if (strlen(message) != SCRAMBLE_LENGTH_323) - return 1; /* Wrong password */ - - hash_password(hash_message,message); + hash_password(hash_message, message, SCRAMBLE_LENGTH_323); randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); to=buff; @@ -231,7 +228,7 @@ check_scramble_323(const char *scrambled, const char *message, return 0; } -static uint8 char_val(uint8 X) +static inline uint8 char_val(uint8 X) { return (uint) (X >= '0' && X <= '9' ? X-'0' : X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10); @@ -280,7 +277,10 @@ void make_password_from_salt_323(char *to, const ulong *salt) } -/******************* MySQL 4.1.1 authentification routines ******************/ +/* + **************** MySQL 4.1.1 authentification routines ************* +*/ + /* Generate string of printable random characters of requested length SYNOPSIS @@ -315,19 +315,16 @@ void create_random_string(char *to, uint length, struct rand_struct *rand_st) str, len IN the beginning and the length of the input string */ -static -void +static void octet2hex(char *to, const uint8 *str, uint len) { - static const char alphabet[] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; const uint8 *str_end= str + len; for (; str != str_end; ++str) { - *to++= alphabet[(*str & 0xF0) >> 4]; - *to++= alphabet[*str & 0x0F]; + *to++= _dig_vec[(*str & 0xF0) >> 4]; + *to++= _dig_vec[*str & 0x0F]; } - *to++= '\0'; + *to= '\0'; } @@ -341,15 +338,14 @@ octet2hex(char *to, const uint8 *str, uint len) overlap; len % 2 == 0 */ -static -void +static void hex2octet(uint8 *to, const char *str, uint len) { const char *str_end= str + len; while (str < str_end) { - *to= char_val(*str++) << 4; - *to++|= char_val(*str++); + register char tmp= char_val(*str++); + *to++= (tmp << 4) | char_val(*str++); } } @@ -366,9 +362,8 @@ hex2octet(uint8 *to, const char *str, uint len) len IN length of s1 and s2 */ -static -void -my_crypt(char *to, const uint8 *s1, const uint8 *s2, uint len) +static void +my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) { const uint8 *s1_end= s1 + len; while (s1 < s1_end) @@ -447,7 +442,7 @@ scramble(char *to, const char *message, const char *password) sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); /* xor allows 'from' and 'to' overlap: lets take advantage of it */ sha1_result(&sha1_context, (uint8 *) to); - my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH); + my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH); } @@ -459,11 +454,13 @@ scramble(char *to, const char *message, const char *password) long (if not, something fishy is going on). SYNOPSIS check_scramble() - scramble IN clients' reply, presumably produced by scramble() - message IN original random string, previously sent to client - (presumably second argument of scramble()), must be - exactly SCRAMBLE_LENGTH long and NULL-terminated. - hash_stage2 IN hex2octet-decoded database entry + scramble clients' reply, presumably produced by scramble() + message original random string, previously sent to client + (presumably second argument of scramble()), must be + exactly SCRAMBLE_LENGTH long and NULL-terminated. + hash_stage2 hex2octet-decoded database entry + All params are IN. + RETURN VALUE 0 password is correct !0 password is invalid @@ -483,7 +480,7 @@ check_scramble(const char *scramble, const char *message, sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); sha1_result(&sha1_context, buf); /* encrypt scramble */ - my_crypt((char *) buf, buf, (const uint8 *) scramble, SCRAMBLE_LENGTH); + my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH); /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ sha1_reset(&sha1_context); sha1_input(&sha1_context, buf, SHA1_HASH_SIZE); diff --git a/sql/protocol.cc b/sql/protocol.cc index 1b9256c7723..7e009aa6a17 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -348,6 +348,25 @@ send_eof(THD *thd, bool no_flush) } DBUG_VOID_RETURN; } + +/* + Please client to send scrambled_password in old format. + SYNOPSYS + send_old_password_request() + thd thread handle + + RETURN VALUE + 0 ok + !0 error +*/ + +bool send_old_password_request(THD *thd) +{ + static char buff[1]= { (char) 254 }; + NET *net= &thd->net; + return my_net_write(net, buff, 1) || net_flush(net); +} + #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/protocol.h b/sql/protocol.h index ffd61b3e848..405d3d4aebe 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -164,6 +164,7 @@ void net_printf(THD *thd,uint sql_errno, ...); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); void send_eof(THD *thd, bool no_flush=0); +bool send_old_password_request(THD *thd); char *net_store_length(char *packet,ulonglong length); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ee544335a99..fafe725201d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -264,10 +264,11 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { switch (password_len) { case 45: /* 4.1: to be removed */ - sql_print_error("Found 4.1 style password for user '%s'. " + sql_print_error("Found 4.1 style password for user '%s@%s'. " "Ignoring user. " "You should change password for this user.", - user.user ? user.user : ""); + user.user ? user.user : "", + user.host.hostname ? user.host.hostname : ""); break; default: sql_print_error("Found invalid password for user: '%s@%s'; " @@ -526,23 +527,30 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) /* 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 - thd INOUT thread handle. If all checks are OK, - thd->priv_user, thd->master_access are updated. - thd->host, thd->ip, thd->user are used for checks. - mqh OUT user resources; on success mqh is reset, else - unchanged - passwd IN scrambled & crypted password, recieved from client - (to check): thd->scramble or thd->scramble_323 is - used to decrypt passwd, so they must contain - original random string, - passwd_len IN length of passwd, must be one of 0, 8, - SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH + acl_getroot() + thd thread handle. If all checks are OK, + thd->priv_user, thd->master_access are updated. + thd->host, thd->ip, thd->user are used for checks. + mqh user resources; on success mqh is reset, else + unchanged + passwd scrambled & crypted password, recieved 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: thread data and mqh are updated + 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are + updated 1 user not found or authentification 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. @@ -553,9 +561,16 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, { DBUG_ENTER("acl_getroot"); - if (!initialized) /* if no data allow anything */ - { - DBUG_RETURN(1); + if (!initialized) + { + /* + here if mysqld's been started with --skip-grant-tables option. + */ + thd->priv_user= (char *) ""; // privileges for + *thd->priv_host= '\0'; // the user are unknown + thd->master_access= ~NO_ACCESS; // everything is allowed + bzero(mqh, sizeof(*mqh)); + DBUG_RETURN(0); } int res= 1; @@ -582,7 +597,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, if (user_i->salt_len == 0 || user_i->salt_len == SCRAMBLE_LENGTH && check_scramble(passwd, thd->scramble, user_i->salt) == 0 || - check_scramble_323(passwd, thd->scramble_323, + check_scramble_323(passwd, thd->scramble, (ulong *) user_i->salt) == 0) { acl_user= user_i; @@ -1346,8 +1361,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, { int error = -1; bool old_row_exists=0; - char empty_string[]= { '\0' }; - char *password= empty_string; + const char *password= ""; uint password_len= 0; char what= (revoke_grant) ? 'N' : 'Y'; DBUG_ENTER("replace_user_table"); diff --git a/sql/sql_class.h b/sql/sql_class.h index e80b5d9c8d5..1557ede8305 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -547,13 +547,7 @@ public: DYNAMIC_ARRAY user_var_events; /* scramble - random string sent to client on handshake */ - char scramble[SCRAMBLE_LENGTH+1]; - /* - The same as scramble but for old password checking routines. It always - contains first N bytes of scramble. - See check_connection() at sql_parse.cc for authentification details. - */ - char scramble_323[SCRAMBLE_LENGTH_323+1]; + char scramble[max(SCRAMBLE_LENGTH, SCRAMBLE_LENGTH_323)+1]; uint8 query_cache_type; // type of query cache processing bool slave_thread; diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc index 930ecfffef7..b0b8050e311 100644 --- a/sql/sql_crypt.cc +++ b/sql/sql_crypt.cc @@ -32,7 +32,7 @@ SQL_CRYPT::SQL_CRYPT(const char *password) { ulong rand_nr[2]; - hash_password(rand_nr,password); + hash_password(rand_nr,password, strlen(password)); crypt_init(rand_nr); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7878f2c8a29..9d75029a997 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -181,17 +181,20 @@ end: Check if user exist and password supplied is correct. SYNOPSIS check_user() - thd INOUT thread handle, thd->{host,user,ip} are used - command IN originator of the check: now check_user is called - during connect and change user procedures; used for - logging. - passwd IN scrambled password recieved from client - passwd_len IN length of scrambled password - db IN database name to connect to, may be NULL - check_count IN dont know exactly + thd thread handle, thd->{host,user,ip} are used + command originator of the check: now check_user is called + during connect and change user procedures; used for + logging. + passwd scrambled password recieved from client + passwd_len length of scrambled password + db database name to connect to, may be NULL + check_count dont know exactly + Note, that host, user and passwd may point to communication buffer. Current implementation does not depened on that, but future changes - should be done with this in mind. + should be done with this in mind; 'thd' is INOUT, all other params + are 'IN'. + RETURN VALUE 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and thd->db_access are updated; OK is sent to client; @@ -226,8 +229,10 @@ static int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(ER_HANDSHAKE_ERROR); /* - Why this is set here? - probably to reset current DB to 'no database - selected' in case of 'change user' failure. + Clear thd->db as it points to something, that will be freed when + connection is closed. We don't want to accidently free a wrong pointer + if connect failed. Also in case of 'CHANGE USER' failure, current + database will be switched to 'no database selected'. */ thd->db= 0; thd->db_length= 0; @@ -244,6 +249,7 @@ static int check_user(THD *thd, enum enum_server_command command, scramble_323()). Here we please client to send scrambled_password in old format. */ + NET *net= &thd->net; if (opt_secure_auth_local) { net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, @@ -258,9 +264,7 @@ static int check_user(THD *thd, enum enum_server_command command, strmake(buff, db, NAME_LEN); db= buff; } - NET *net= &thd->net; - if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) || - net_flush(net) || + if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very { // specific packet size inc_host_errors(&thd->remote.sin_addr); @@ -288,7 +292,7 @@ static int check_user(THD *thd, enum enum_server_command command, { VOID(pthread_mutex_lock(&LOCK_thread_count)); bool count_ok= thread_count < max_connections + delayed_insert_threads - || thd->master_access & SUPER_ACL; + || (thd->master_access & SUPER_ACL); VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (!count_ok) { // too many connections @@ -305,7 +309,11 @@ static int check_user(THD *thd, enum enum_server_command command, thd->user, thd->host_or_ip, db ? db : (char*) ""); - /* Why is it set here? */ + /* + 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. + */ thd->db_access=0; /* Don't allow user to connect if he has done too many queries */ @@ -554,9 +562,10 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0) Perform handshake, authorize client and update thd ACL variables. SYNOPSIS check_connection() - thd INOUT thread handle + thd thread handle + RETURN - 0 success, OK is sent to user + 0 success, OK is sent to user, thd is updated. -1 error, which is sent to user > 0 error code (not sent to user) */ @@ -644,14 +653,12 @@ check_connection(THD *thd) each handshake. */ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand); - strmake(thd->scramble_323, thd->scramble, SCRAMBLE_LENGTH_323); - /* 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= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1; + end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; int2store(end, client_flags); /* write server characteristics: up to 16 bytes allowed */ @@ -754,8 +761,6 @@ check_connection(THD *thd) return(ER_HANDSHAKE_ERROR); } - /* why has it been put here? */ - if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && @@ -778,9 +783,8 @@ check_connection(THD *thd) if (thd->user) x_free(thd->user); - thd->user= my_strdup(user, MYF(0)); - if (!thd->user) - return(ER_OUT_OF_RESOURCES); + if (!(thd->user= my_strdup(user, MYF(0)))) + return (ER_OUT_OF_RESOURCES); return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true); } -- cgit v1.2.1 From 4df473b81c92be37364abaa83b0bafe21fc135a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Jul 2003 18:57:21 +0400 Subject: few compile-time bugs fixed include/mysql.h: fixed compile-time bug sql/sql_class.cc: fixed compile-time bug sql/sql_class.h: fixed compile-time bug --- include/mysql.h | 2 +- sql/sql_class.cc | 2 +- sql/sql_class.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 079808d9ba7..10bacffb2b1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -229,7 +229,7 @@ typedef struct st_mysql my_bool reconnect; /* set to 1 if automatic reconnect */ /* session-wide random string */ - char scramble[max(SCRAMBLE_LENGTH,SCRAMBLE_LENGTH_323)+1]; + char scramble[SCRAMBLE_LENGTH+1]; /* Set if this is the original connection, not a master or a slave we have diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ebb3e819ddc..c7fb2ce3368 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -139,7 +139,7 @@ THD::THD():user_time(0), is_fatal_error(0), set_query_id=1; db_access=NO_ACCESS; version=refresh_version; // For boot - *scramble= *scramble_323= '\0'; + *scramble= '\0'; init(); /* Initialize sub structures */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 1557ede8305..4eb1d6057a9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -547,7 +547,7 @@ public: DYNAMIC_ARRAY user_var_events; /* scramble - random string sent to client on handshake */ - char scramble[max(SCRAMBLE_LENGTH, SCRAMBLE_LENGTH_323)+1]; + char scramble[SCRAMBLE_LENGTH+1]; uint8 query_cache_type; // type of query cache processing bool slave_thread; -- cgit v1.2.1 From ecc7001fbfc1b30a1bbd856b7a093045ccdf3c00 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jul 2003 21:21:42 +0200 Subject: INSTALL-WIN-SOURCE: Change mode to -rw-rw-r-- INSTALL-WIN-SOURCE: Change mode to -rw-rw-r-- --- INSTALL-WIN-SOURCE | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 INSTALL-WIN-SOURCE diff --git a/INSTALL-WIN-SOURCE b/INSTALL-WIN-SOURCE old mode 100755 new mode 100644 -- cgit v1.2.1 From 2c3cba310aa401842996a52abdbde95bb950fcc5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 Jul 2003 15:47:00 +0400 Subject: merge commit sql-common/client.c: comment fix --- sql-common/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-common/client.c b/sql-common/client.c index aac5be4b690..b43084855b9 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1878,7 +1878,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, { /* By sending this very specific reply server asks us to send scrambled - password in old format. The reply contains scramble_323. + password in old format. */ scramble_323(buff, mysql->scramble, passwd); if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net)) -- cgit v1.2.1 From eb5f968c455276ba2d13e5b44edadef1294d5ab5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Aug 2003 21:14:15 +0200 Subject: table checksum background: my_checksum() mysys function NISAM checksum code moved from mysys to isam/ - it's obsolete MyISAM checksum code moved to mysys table's checksum accessible from sql layer SHOW TABLE STATUS shows checksum (WL#646) code cleanup include/my_sys.h: table checksum background: my_checksum() mysys function include/myisam.h: table checksum background: my_checksum() mysys function MyISAM checksum code moved to mysys isam/isamchk.c: table checksum background: NISAM checksum code moved from mysys to isam/ - it's obsolete isam/isamdef.h: table checksum background: NISAM checksum code moved from mysys to isam/ - it's obsolete isam/open.c: table checksum background: NISAM checksum code moved from mysys to isam/ - it's obsolete isam/pack_isam.c: table checksum background: NISAM checksum code moved from mysys to isam/ - it's obsolete myisam/mi_checksum.c: table checksum background: my_checksum() mysys function MyISAM checksum code moved to mysys mysys/checksum.c: table checksum background: my_checksum() mysys function MyISAM checksum code moved to mysys sql/ha_myisam.cc: table checksum background: table's checksum accessible from sql layer sql/ha_myisam.h: table checksum background: table's checksum accessible from sql layer sql/handler.h: table checksum background: table's checksum accessible from sql layer code cleanup sql/sql_lex.h: table checksum background: table's checksum accessible from sql layer code cleanup sql/sql_select.cc: warning removed sql/sql_show.cc: SHOW TABLE STATUS shows checksum (WL#646) sql/sql_yacc.yy: cleanup (DROP TABLES syntax added as a side effect :)) --- include/my_sys.h | 6 +++-- include/myisam.h | 2 -- isam/isamchk.c | 2 +- isam/isamdef.h | 1 + isam/open.c | 19 ++++++++++++++ isam/pack_isam.c | 2 +- myisam/mi_checksum.c | 19 ++++++-------- mysys/checksum.c | 21 ++++++++-------- sql/ha_myisam.cc | 8 ++++++ sql/ha_myisam.h | 1 + sql/handler.h | 71 ++++++++++++++++++++++++++-------------------------- sql/sql_lex.h | 20 +++++++-------- sql/sql_select.cc | 2 +- sql/sql_show.cc | 6 +++++ sql/sql_yacc.yy | 22 ++++++++-------- 15 files changed, 118 insertions(+), 84 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index e4125a2e7e6..6721d77a8af 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -213,7 +213,7 @@ extern uint get_charset_number(const char *cs_name); extern const char *get_charset_name(uint cs_number); extern CHARSET_INFO *get_charset(uint cs_number, myf flags); extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); -extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, uint cs_flags, myf my_flags); extern void free_charsets(void); extern char *get_charsets_dir(char *buf); @@ -507,6 +507,8 @@ typedef struct st_keycache ulonglong size; } KEY_CACHE; +typedef uint32 ha_checksum; + #include /* Prototypes for mysys and my_func functions */ @@ -749,7 +751,7 @@ extern void print_defaults(const char *conf_file, const char **groups); extern my_bool my_compress(byte *, ulong *, ulong *); extern my_bool my_uncompress(byte *, ulong *, ulong *); extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen); -extern ulong checksum(const byte *mem, uint count); +extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count); extern uint my_bit_log2(ulong value); uint my_count_bits(ulonglong v); extern void my_sleep(ulong m_seconds); diff --git a/include/myisam.h b/include/myisam.h index e85d3057672..0ffcdae8567 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -53,8 +53,6 @@ extern "C" { #define mi_portable_sizeof_char_ptr 8 -typedef uint32 ha_checksum; - /* Param to/from mi_info */ typedef struct st_mi_isaminfo /* Struct from h_info */ diff --git a/isam/isamchk.c b/isam/isamchk.c index dc772290e13..939a4be732f 100644 --- a/isam/isamchk.c +++ b/isam/isamchk.c @@ -1328,7 +1328,7 @@ int extend; print_error("Found wrong record at %lu",(ulong) start_recpos); got_error=1; } - crc^=checksum(record,info->s->base.reclength); + crc^=_nisam_checksum(record,info->s->base.reclength); link_used+=info->s->pack.ref_length; used+=block_info.rec_len+info->s->pack.ref_length; } diff --git a/isam/isamdef.h b/isam/isamdef.h index 0884b18e997..54656b6842e 100644 --- a/isam/isamdef.h +++ b/isam/isamdef.h @@ -358,6 +358,7 @@ extern int _nisam_read_pack_record(N_INFO *info,ulong filepos,byte *buf); extern int _nisam_read_rnd_pack_record(N_INFO*, byte *,ulong, int); extern int _nisam_pack_rec_unpack(N_INFO *info,byte *to,byte *from, uint reclength); +extern ulong _nisam_checksum(const byte *mem, uint count); typedef struct st_sortinfo { uint key_length; diff --git a/isam/open.c b/isam/open.c index 48fab27cac1..824fbe804ee 100644 --- a/isam/open.c +++ b/isam/open.c @@ -453,3 +453,22 @@ static void setup_key_functions(register N_KEYDEF *keyinfo) } return; } + +/* + Calculate a long checksum for a memoryblock. Used to verify pack_isam + + SYNOPSIS + checksum() + mem Pointer to memory block + count Count of bytes +*/ + +ulong _nisam_checksum(const byte *mem, uint count) +{ + ulong crc; + for (crc= 0; count-- ; mem++) + crc= ((crc << 1) + *((uchar*) mem)) + + test(crc & ((ulong) 1L << (8*sizeof(ulong)-1))); + return crc; +} + diff --git a/isam/pack_isam.c b/isam/pack_isam.c index fd12aac1e09..9108070f918 100644 --- a/isam/pack_isam.c +++ b/isam/pack_isam.c @@ -738,7 +738,7 @@ static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts) { if (! error) { - crc^=checksum(record,reclength); + crc^=_nisam_checksum(record,reclength); for (pos=record,count=huff_counts ; count < end_count ; count++, diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c index a760b03a032..982f77ee81f 100644 --- a/myisam/mi_checksum.c +++ b/myisam/mi_checksum.c @@ -28,30 +28,29 @@ ha_checksum mi_checksum(MI_INFO *info, const byte *buf) { const byte *pos; const byte *end; + ulong length; switch (rec->type) { case FIELD_BLOB: { - ulong length=_mi_calc_blob_length(rec->length- + length=_mi_calc_blob_length(rec->length- mi_portable_sizeof_char_ptr, buf); memcpy((char*) &pos, buf+rec->length- mi_portable_sizeof_char_ptr, sizeof(char*)); - end=pos+length; break; } case FIELD_VARCHAR: { - uint length; length=uint2korr(buf); - pos=buf+2; end=pos+length; + pos=buf+2; break; } default: - pos=buf; end=buf+rec->length; + length=rec->length; + pos=buf; break; } - for ( ; pos != end ; pos++) - crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8)); + crc=my_checksum(crc, pos, length); } return crc; } @@ -59,9 +58,5 @@ ha_checksum mi_checksum(MI_INFO *info, const byte *buf) ha_checksum mi_static_checksum(MI_INFO *info, const byte *pos) { - ha_checksum crc; - const byte *end=pos+info->s->base.reclength; - for (crc=0; pos != end; pos++) - crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8)); - return crc; + return my_checksum(0, pos, info->s->base.reclength); } diff --git a/mysys/checksum.c b/mysys/checksum.c index 1dd135c7ad9..2ae139b81c3 100644 --- a/mysys/checksum.c +++ b/mysys/checksum.c @@ -19,19 +19,20 @@ #include "my_sys.h" /* - Calculate a long checksum for a memoryblock. Used to verify pack_isam - + Calculate a long checksum for a memoryblock. + SYNOPSIS - checksum() - mem Pointer to memory block - count Count of bytes + my_checksum() + crc start value for crc + pos pointer to memory block + length length of the block */ -ulong checksum(const byte *mem, uint count) +ha_checksum my_checksum(ha_checksum crc, const byte *pos, uint length) { - ulong crc; - for (crc= 0; count-- ; mem++) - crc= ((crc << 1) + *((uchar*) mem)) + - test(crc & ((ulong) 1L << (8*sizeof(ulong)-1))); + const byte *end=pos+length; + for ( ; pos != end ; pos++) + crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8)); return crc; } + diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 4f1021232a4..d2cbdec36f1 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -236,6 +236,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0)); if (!table->db_record_offset) int_table_flags|=HA_REC_NOT_IN_SEQ; + if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) + int_table_flags|=HA_HAS_CHECKSUM; return (0); } @@ -1398,3 +1400,9 @@ int ha_myisam::ft_read(byte * buf) table->status=error ? STATUS_NOT_FOUND: 0; return error; } + +uint ha_myisam::checksum() const +{ + return (uint)file->s->state.checksum; +} + diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 8486e25556b..e4e3192af10 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -64,6 +64,7 @@ class ha_myisam: public handler uint max_keys() const { return MI_MAX_KEY; } uint max_key_parts() const { return MAX_REF_PARTS; } uint max_key_length() const { return MI_MAX_KEY_LENGTH; } + uint checksum() const; int open(const char *name, int mode, uint test_if_locked); int close(void); diff --git a/sql/handler.h b/sql/handler.h index 08a7c83d328..c26efa47ded 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -42,38 +42,39 @@ #define HA_ADMIN_INVALID -5 /* Bits in table_flags() to show what database can do */ -#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record - (To update with RND-read) */ -#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */ -#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */ -#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber; - It returns a position to ha_r_rnd */ -#define HA_HAS_GEOMETRY 16 -#define HA_NO_INDEX 32 /* No index needed for next/prev */ -#define HA_KEY_READ_WRONG_STR 64 /* keyread returns converted strings */ -#define HA_NULL_KEY 128 /* One can have keys with NULL */ -#define HA_DUPP_POS 256 /* ha_position() gives dupp row */ -#define HA_NO_BLOBS 512 /* Doesn't support blobs */ -#define HA_BLOB_KEY (HA_NO_BLOBS*2) /* key on blob */ -#define HA_AUTO_PART_KEY (HA_BLOB_KEY*2) -#define HA_REQUIRE_PRIMARY_KEY (HA_AUTO_PART_KEY*2) -#define HA_NOT_EXACT_COUNT (HA_REQUIRE_PRIMARY_KEY*2) -#define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2) -#define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2) -#define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2) -#define HA_NOT_READ_AFTER_KEY (HA_DROP_BEFORE_CREATE*2) -#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2) -#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2) -#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2) -#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2) -#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2) -#define HA_NO_AUTO_INCREMENT (HA_CAN_SQL_HANDLER*2) +#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record + (To update with RND-read) */ +#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */ +#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */ +#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber; + It returns a position to ha_r_rnd */ +#define HA_HAS_GEOMETRY (1 << 4) +#define HA_NO_INDEX (1 << 5) /* No index needed for next/prev */ +#define HA_KEY_READ_WRONG_STR (1 << 6) /* keyread returns converted strings */ +#define HA_NULL_KEY (1 << 7) /* One can have keys with NULL */ +#define HA_DUPP_POS (1 << 8) /* ha_position() gives dupp row */ +#define HA_NO_BLOBS (1 << 9) /* Doesn't support blobs */ +#define HA_BLOB_KEY (1 << 10) /* key on blob */ +#define HA_AUTO_PART_KEY (1 << 11) +#define HA_REQUIRE_PRIMARY_KEY (1 << 12) +#define HA_NOT_EXACT_COUNT (1 << 13) +#define HA_NO_WRITE_DELAYED (1 << 14) +#define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15) +#define HA_DROP_BEFORE_CREATE (1 << 16) +#define HA_NOT_READ_AFTER_KEY (1 << 17) +#define HA_NOT_DELETE_WITH_CACHE (1 << 18) +#define HA_NO_TEMP_TABLES (1 << 19) +#define HA_NO_PREFIX_CHAR_KEYS (1 << 20) +#define HA_CAN_FULLTEXT (1 << 21) +#define HA_CAN_SQL_HANDLER (1 << 22) +#define HA_NO_AUTO_INCREMENT (1 << 23) +#define HA_HAS_CHECKSUM (1 << 24) /* Next record gives next record according last record read (even if database is updated after read). Not used at this point. */ -#define HA_LASTKEY_ORDER (HA_NO_AUTO_INCREMENT*2) +#define HA_LASTKEY_ORDER (1 << 25) /* bits in index_flags(index_number) for what you can do with index */ @@ -304,8 +305,8 @@ public: virtual bool check_and_repair(THD *thd) {return 1;} virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt); virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt); - virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); + virtual int backup(THD* thd, HA_CHECK_OPT* check_opt); /* restore assumes .frm file must exist, and that generate_table() has been called; It will just copy the data file and run repair. @@ -323,8 +324,8 @@ public: virtual char* get_foreign_key_create_info() { return(NULL);} /* gets foreign key create string from InnoDB */ virtual void init_table_handle_for_HANDLER() - { return; } /* prepare InnoDB for HANDLER */ - virtual void free_foreign_key_create_info(char* str) {} + { return; } /* prepare InnoDB for HANDLER */ + virtual void free_foreign_key_create_info(char* str) {} /* The following can be called without an open handler */ virtual const char *table_type() const =0; virtual const char **bas_ext() const =0; @@ -340,6 +341,7 @@ public: virtual uint max_key_part_length() { return 255; } virtual uint min_record_length(uint options) const { return 1; } virtual bool low_byte_first() const { return 1; } + virtual uint checksum() const { return 0; } virtual bool is_crashed() const { return 0; } virtual bool auto_repair() const { return 0; } @@ -353,13 +355,12 @@ public: /* Type of table for caching query */ virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; } - /* - Is query with this cable cachable (have sense only for ASKTRANSACT + /* + Is query with this table cachable (have sense only for ASKTRANSACT tables) */ - static bool caching_allowed(THD* thd, char* table_key, + static bool caching_allowed(THD* thd, char* table_key, uint key_length, uint8 cahe_type); - }; /* Some extern variables used with handlers */ @@ -388,7 +389,7 @@ int ha_delete_table(enum db_type db_type, const char *path); void ha_drop_database(char* path); void ha_key_cache(void); void ha_resize_key_cache(void); -int ha_start_stmt(THD *thd); +int ha_start_stmt(THD *thd); int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, my_off_t end_offset); int ha_commit_complete(THD *thd); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index faf7e16e54a..df73f12d32f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -447,15 +447,21 @@ typedef struct st_lex SELECT_LEX *all_selects_list; uchar *ptr,*tok_start,*tok_end,*end_of_query; char *length,*dec,*change,*name; + char *help_arg; char *backup_dir; /* For RESTORE/BACKUP */ char* to_log; /* For PURGE MASTER LOGS TO */ time_t purge_time; /* For PURGE MASTER LOGS BEFORE */ char* x509_subject,*x509_issuer,*ssl_cipher; char* found_colon; /* For multi queries - next query */ - enum SSL_type ssl_type; /* defined in violite.h */ String *wild; sql_exchange *exchange; select_result *result; + Item *default_value, *comment; + LEX_USER *grant_user; + gptr yacc_yyss,yacc_yyvs; + THD *thd; + CHARSET_INFO *charset; + SQL_LIST *gorder_list; List col_list; List ref_list; @@ -473,11 +479,6 @@ typedef struct st_lex SQL_LIST proc_list, auxilliary_table_list; TYPELIB *interval; create_field *last_field; - Item *default_value, *comment; - uint uint_geom_type; - LEX_USER *grant_user; - gptr yacc_yyss,yacc_yyvs; - THD *thd; udf_func udf; HA_CHECK_OPT check_opt; // check/repair options HA_CREATE_INFO create_info; @@ -486,6 +487,7 @@ typedef struct st_lex ulong thread_id,type; enum_sql_command sql_command; thr_lock_type lock_option; + enum SSL_type ssl_type; /* defined in violite.h */ enum my_lex_states next_state; enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; @@ -493,17 +495,15 @@ typedef struct st_lex enum ha_rkey_function ha_rkey_mode; enum enum_enable_or_disable alter_keys_onoff; enum enum_var_type option_type; + uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; uint param_count; + uint slave_thd_opt; bool drop_primary, drop_if_exists, drop_temporary, local_file; bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog; bool derived_tables, describe; bool safe_to_cache_query; - uint slave_thd_opt; - CHARSET_INFO *charset; - char *help_arg; - SQL_LIST *gorder_list; st_lex() {} inline void uncacheable() { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0aa7e67a12b..12d93dfc674 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2349,7 +2349,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) Constant tables are ignored. To avoid bad matches, we don't make ref_table_rows less than 100. */ - keyuse->ref_table_rows= ~(table_map) 0; // If no ref + keyuse->ref_table_rows= ~(ha_rows) 0; // If no ref if (keyuse->used_tables & (map= (keyuse->used_tables & ~join->const_table_map & ~OUTER_REF_TABLE_BIT))) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9084269f486..7dd2004b664 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -503,6 +503,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Charset",32)); item->maybe_null=1; + field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21)); + item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Create_options",255)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Comment",80)); @@ -588,6 +590,10 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) } str= (table->table_charset ? table->table_charset->name : "default"); protocol->store(str, system_charset_info); + if (file->table_flags() & HA_HAS_CHECKSUM) + protocol->store((ulonglong)file->checksum()); + else + protocol->store_null(); // Checksum { char option_buff[350],*ptr; ptr=option_buff; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a5ac04dc775..2e8ed389a98 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -730,17 +730,19 @@ verb_clause: | describe | do | drop + | flush | grant + | handler + | help | insert - | flush + | kill | load | lock - | kill | optimize | preload | purge | rename - | repair + | repair | replace | reset | restore @@ -748,15 +750,14 @@ verb_clause: | rollback | select | set + | show | slave | start - | show | truncate - | handler | unlock | update | use - | help; + ; /* help */ @@ -1817,7 +1818,7 @@ optimize: { LEX *lex=Lex; lex->sql_command = SQLCOM_OPTIMIZE; - lex->no_write_to_binlog= $2; + lex->no_write_to_binlog= $2; lex->check_opt.init(); } table_list opt_mi_check_type @@ -3327,7 +3328,7 @@ do: DO_SYM */ drop: - DROP opt_temporary TABLE_SYM if_exists table_list opt_restrict + DROP opt_temporary table_or_tables if_exists table_list opt_restrict { LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_TABLE; @@ -3363,7 +3364,7 @@ drop: LEX *lex=Lex; lex->sql_command = SQLCOM_DROP_USER; lex->users_list.empty(); - } + } user_list {} ; @@ -4851,7 +4852,7 @@ grant_privilege_list: | grant_privilege_list ',' grant_privilege; grant_privilege: - SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {} + SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {} | INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {} | UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {} | REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list {} @@ -5228,3 +5229,4 @@ subselect_end: LEX *lex=Lex; lex->current_select = lex->current_select->return_after_parsing(); }; + -- cgit v1.2.1 From 68f8339158d8b54111bf179fb08040b51b0778c0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Aug 2003 20:48:51 +0300 Subject: fixed collation of Item_cache family (BUG#951) mysql-test/r/subselect.result: test of collation mysql-test/t/subselect.test: test of collation sql/item.cc: coping collation in the cache sql/item.h: coping collation in the cache --- mysql-test/r/subselect.result | 7 +++++++ mysql-test/t/subselect.test | 11 +++++++++++ sql/item.cc | 2 +- sql/item.h | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 1db31881607..94d3258aef2 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1251,3 +1251,10 @@ a 2 10 drop table t1,t2; +CREATE TABLE t1 (s1 CHAR(5) COLLATE latin1_german1_ci, +s2 CHAR(5) COLLATE latin1_swedish_ci); +INSERT INTO t1 VALUES ('z','?'); +select * from t1 where s1 > (select max(s2) from t1); +ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' +select * from t1 where s1 > any (select max(s2) from t1); +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 28408bbf365..1359e1b5dda 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -853,3 +853,14 @@ insert into t3 values (1),(2),(10),(50); select a from t3 where t3.a in (select a from t1 where a <= 3 union select * from t2 where a <= 30); drop table t1,t2; +# +# collation test +# +CREATE TABLE t1 (s1 CHAR(5) COLLATE latin1_german1_ci, + s2 CHAR(5) COLLATE latin1_swedish_ci); +INSERT INTO t1 VALUES ('z','?'); +-- error 1265 +select * from t1 where s1 > (select max(s2) from t1); +-- error 1265 +select * from t1 where s1 > any (select max(s2) from t1); +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 17b0519b61c..7c9579416db 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1704,7 +1704,7 @@ void Item_cache_str::store(Item *item) str_value.copy(*value); value= &str_value; } - + collation.set(item->collation); } double Item_cache_str::val() { diff --git a/sql/item.h b/sql/item.h index 3412b43da44..9355b43f538 100644 --- a/sql/item.h +++ b/sql/item.h @@ -852,6 +852,7 @@ public: { value= item->val_int_result(); null_value= item->null_value; + collation.set(item->collation); } double val() { return (double) value; } longlong val_int() { return value; } @@ -869,6 +870,7 @@ public: { value= item->val_result(); null_value= item->null_value; + collation.set(item->collation); } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } -- cgit v1.2.1 From 78f54936a7f7668007a153891d4009d876741562 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Aug 2003 00:41:08 +0300 Subject: merge mysql-test/r/subselect.result: correct result after merging with fixed Item_in_optimiser::fix_left() mysql-test/t/subselect.test: error code changed --- mysql-test/r/subselect.result | 1 + mysql-test/t/subselect.test | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 510ce867100..cf02eda9aba 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1350,4 +1350,5 @@ INSERT INTO t1 VALUES ('z','?'); select * from t1 where s1 > (select max(s2) from t1); ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' select * from t1 where s1 > any (select max(s2) from t1); +ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 89f9c528237..457b64a5a11 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -907,8 +907,8 @@ drop table t1,t2; CREATE TABLE t1 (s1 CHAR(5) COLLATE latin1_german1_ci, s2 CHAR(5) COLLATE latin1_swedish_ci); INSERT INTO t1 VALUES ('z','?'); --- error 1265 +-- error 1266 select * from t1 where s1 > (select max(s2) from t1); --- error 1265 +-- error 1266 select * from t1 where s1 > any (select max(s2) from t1); drop table t1; -- cgit v1.2.1 From e103da7acc6f3563a2f7207e59c34b9d9ff64295 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Aug 2003 16:15:06 +0200 Subject: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} checksum table command Com_xxx status variables updated sql/item_create.cc: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/item_func.cc: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/item_func.h: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/item_geofunc.h: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/item_strfunc.cc: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/item_strfunc.h: fixed a crash on COMPRESS() and other zlib-dependent functions when compiled w/o zlib moved them all from different places to item_strfunc.{h,cc} sql/mysql_priv.h: checksum table command sql/mysqld.cc: Com_xxx updated sql/sql_lex.h: checksum table command sql/sql_parse.cc: checksum table command sql/sql_table.cc: checksum table command sql/sql_yacc.yy: checksum table command --- sql/item_create.cc | 21 ++++------------- sql/item_func.cc | 36 ++--------------------------- sql/item_func.h | 21 ----------------- sql/item_geofunc.h | 24 ------------------- sql/item_strfunc.cc | 55 ++++++++++++++++++++++++++++++++++++-------- sql/item_strfunc.h | 49 ++++++++++++++++++++++++++++++++++++++- sql/mysql_priv.h | 1 + sql/mysqld.cc | 11 ++++++--- sql/sql_lex.h | 4 ++-- sql/sql_parse.cc | 8 +++++++ sql/sql_table.cc | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++- sql/sql_yacc.yy | 15 ++++++++++-- 12 files changed, 197 insertions(+), 114 deletions(-) diff --git a/sql/item_create.cc b/sql/item_create.cc index e18d1cfa189..b0704931535 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -107,14 +107,6 @@ Item *create_func_cot(Item* a) new Item_func_tan(a)); } - -#ifdef HAVE_COMPRESS -Item *create_func_crc32(Item* a) -{ - return new Item_func_crc32(a); -} -#endif - Item *create_func_date_format(Item* a,Item *b) { return new Item_func_date_format(a,b,0); @@ -666,13 +658,10 @@ Item *create_func_point(Item *a, Item *b) return new Item_func_point(a, b); } -#if !defined(HAVE_COMPRESS) - -Item *create_func_compress (Item*a __attribute__((unused))){return 0;} -Item *create_func_uncompress (Item*a __attribute__((unused))){return 0;} -Item *create_func_uncompressed_length(Item*a __attribute__((unused))){return 0;} - -#else +Item *create_func_crc32(Item* a) +{ + return new Item_func_crc32(a); +} Item *create_func_compress(Item* a) { @@ -689,8 +678,6 @@ Item *create_func_uncompressed_length(Item* a) return new Item_func_uncompressed_length(a); } -#endif - Item *create_func_datediff(Item *a, Item *b) { return new Item_func_minus(new Item_func_to_days(a), diff --git a/sql/item_func.cc b/sql/item_func.cc index a7c5b35b8db..6350d3874a1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -27,19 +27,16 @@ #include #include #include -#ifdef HAVE_COMPRESS -#include -#endif static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), + c1.collation->name,c1.derivation_name(), c2.collation->name,c2.derivation_name(), fname); } -static void my_coll_agg_error(DTCollation &c1, +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, DTCollation &c3, const char *fname) @@ -1039,35 +1036,6 @@ longlong Item_func_min_max::val_int() return value; } - -#ifdef HAVE_COMPRESS -longlong Item_func_crc32::val_int() -{ - String *res=args[0]->val_str(&value); - if (!res) - { - null_value=1; - return 0; /* purecov: inspected */ - } - null_value=0; - return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length()); -} - -longlong Item_func_uncompressed_length::val_int() -{ - String *res= args[0]->val_str(&value); - if (!res) - { - null_value=1; - return 0; /* purecov: inspected */ - } - null_value=0; - if (res->is_empty()) return 0; - return uint4korr(res->c_ptr()) & 0x3FFFFFFF; -} - -#endif /* HAVE_COMPRESS */ - longlong Item_func_length::val_int() { String *res=args[0]->val_str(&value); diff --git a/sql/item_func.h b/sql/item_func.h index 56ee0379cd5..b7e99bb37b7 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -553,27 +553,6 @@ public: }; -#ifdef HAVE_COMPRESS -class Item_func_crc32 :public Item_int_func -{ - String value; -public: - Item_func_crc32(Item *a) :Item_int_func(a) {} - longlong val_int(); - const char *func_name() const { return "crc32"; } - void fix_length_and_dec() { max_length=10; } -}; -class Item_func_uncompressed_length : public Item_int_func -{ - String value; -public: - Item_func_uncompressed_length(Item *a):Item_int_func(a){} - longlong val_int(); - const char *func_name() const{return "uncompressed_length";} - void fix_length_and_dec() { max_length=10; } -}; -#endif - class Item_func_length :public Item_int_func { String value; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index d86914eb6c5..79e45cca26f 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -167,30 +167,6 @@ public: const char *func_name() const { return "multipoint"; } }; -#ifdef HAVE_COMPRESS - -class Item_func_compress: public Item_str_func -{ - String buffer; -public: - Item_func_compress(Item *a):Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} - const char *func_name() const{return "compress";} -}; - -class Item_func_uncompress: public Item_str_func -{ - String buffer; -public: - Item_func_uncompress(Item *a): Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} - const char *func_name() const{return "uncompress";} -}; - -#endif - /* Spatial relations */ diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b92839e6c1e..7c6e6e0686c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2548,9 +2548,47 @@ null: return 0; } +longlong Item_func_uncompressed_length::val_int() +{ + String *res= args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + if (res->is_empty()) return 0; + return uint4korr(res->c_ptr()) & 0x3FFFFFFF; +} + #ifdef HAVE_COMPRESS #include "zlib.h" +longlong Item_func_crc32::val_int() +{ + String *res=args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length()); +} + +longlong Item_func_uncompressed_length::val_int() +{ + String *res= args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + if (res->is_empty()) return 0; + return uint4korr(res->c_ptr()) & 0x3FFFFFFF; +} + String *Item_func_compress::val_str(String *str) { String *res= args[0]->val_str(str); @@ -2575,7 +2613,7 @@ String *Item_func_compress::val_str(String *str) buffer.realloc((uint32)new_size + 4 + 1); Byte *body= ((Byte*)buffer.c_ptr()) + 4; - + if ((err= compress(body, &new_size, (const Bytef*)res->c_ptr(), res->length())) != Z_OK) { @@ -2597,7 +2635,7 @@ String *Item_func_compress::val_str(String *str) } buffer.length((uint32)new_size + 4); - + return &buffer; } @@ -2609,7 +2647,7 @@ String *Item_func_uncompress::val_str(String *str) ulong new_size= uint4korr(res->c_ptr()) & 0x3FFFFFFF; int err= Z_OK; uint code; - + if (new_size > MAX_BLOB_WIDTH) { push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, @@ -2618,21 +2656,20 @@ String *Item_func_uncompress::val_str(String *str) null_value= 0; return 0; } - + buffer.realloc((uint32)new_size); - - if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size, + + if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size, ((const Bytef*)res->c_ptr())+4,res->length())) == Z_OK) { buffer.length((uint32)new_size); return &buffer; } - - code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR : + + code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR : err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR; push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); null_value= 1; return 0; } - #endif diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index dfcc22b3443..d7547d69aed 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -623,9 +623,56 @@ public: Item_func_collation(Item *a) :Item_str_func(a) {} String *val_str(String *); const char *func_name() const { return "collation"; } - void fix_length_and_dec() + void fix_length_and_dec() { max_length=40; // should be enough collation.set(system_charset_info); }; }; + +#ifdef HAVE_COMPRESS +#define ZLIB_DEPENDED_FUNCTION ; +#else +#define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; } +#endif + +class Item_func_compress: public Item_str_func +{ + String buffer; +public: + Item_func_compress(Item *a):Item_str_func(a){} + void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} + const char *func_name() const{return "compress";} + String *val_str(String *) ZLIB_DEPENDED_FUNCTION +}; + +class Item_func_uncompress: public Item_str_func +{ + String buffer; +public: + Item_func_uncompress(Item *a): Item_str_func(a){} + void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} + const char *func_name() const{return "uncompress";} + String *val_str(String *) ZLIB_DEPENDED_FUNCTION +}; + +class Item_func_crc32 :public Item_int_func +{ + String value; +public: + Item_func_crc32(Item *a) :Item_int_func(a) {} + const char *func_name() const { return "crc32"; } + void fix_length_and_dec() { max_length=10; } + longlong val_int() ZLIB_DEPENDED_FUNCTION +}; + +class Item_func_uncompressed_length : public Item_int_func +{ + String value; +public: + Item_func_uncompressed_length(Item *a):Item_int_func(a){} + const char *func_name() const{return "uncompressed_length";} + void fix_length_and_dec() { max_length=10; } + longlong val_int(); +}; + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c41d973f2e..9834d169ac4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -398,6 +398,7 @@ bool check_global_access(THD *thd, ulong want_access); int mysql_backup_table(THD* thd, TABLE_LIST* table_list); int mysql_restore_table(THD* thd, TABLE_LIST* table_list); +int mysql_checksum_table(THD* thd, TABLE_LIST* table_list); int mysql_check_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); int mysql_repair_table(THD* thd, TABLE_LIST* table_list, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8ddcbdc572f..fedaf32a45c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4383,14 +4383,15 @@ struct show_var_st status_vars[]= { {"Bytes_received", (char*) &bytes_received, SHOW_LONG}, {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG}, {"Com_admin_commands", (char*) &com_other, SHOW_LONG}, - {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG}, {"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG}, + {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG}, {"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG}, {"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG}, {"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG}, {"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG}, {"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG}, {"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG}, + {"Com_checksum", (char*) (com_stat+(uint) SQLCOM_CHECKSUM),SHOW_LONG}, {"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG}, {"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG}, {"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG}, @@ -4403,6 +4404,7 @@ struct show_var_st status_vars[]= { {"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG}, {"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG}, {"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG}, + {"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG}, {"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG}, {"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG}, {"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG}, @@ -4417,6 +4419,7 @@ struct show_var_st status_vars[]= { {"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG}, {"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG}, {"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG}, + {"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG}, {"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG}, {"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG}, {"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG}, @@ -4426,12 +4429,14 @@ struct show_var_st status_vars[]= { {"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG}, {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG}, {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG}, + {"Com_revoke_all", (char*) (com_stat+(uint) SQLCOM_REVOKE_ALL),SHOW_LONG}, {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG}, {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG}, {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG}, - {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG}, {"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG}, + {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG}, {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG}, + {"Com_show_collations", (char*) (com_stat+(uint) SQLCOM_SHOW_COLLATIONS),SHOW_LONG}, {"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG}, {"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG}, {"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG}, @@ -4439,6 +4444,7 @@ struct show_var_st status_vars[]= { {"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG}, {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG}, {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG}, + {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG}, {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG}, {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG}, @@ -4449,7 +4455,6 @@ struct show_var_st status_vars[]= { {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG}, {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG}, {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG}, - {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG}, {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG}, {"Com_show_table_types", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLE_TYPES),SHOW_LONG}, {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG}, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index abf1a9e4ab3..fb2f3181c23 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -60,7 +60,7 @@ enum enum_sql_command { SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS, - SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, + SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, @@ -71,7 +71,7 @@ enum enum_sql_command { SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES, - SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, + SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM, /* This should be the last !!! */ SQLCOM_END diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ed68f487924..0e344756b18 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2264,6 +2264,14 @@ mysql_execute_command(THD *thd) break; } #endif + case SQLCOM_CHECKSUM: + { + if (check_db_used(thd,tables) || + check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables)) + goto error; /* purecov: inspected */ + res = mysql_checksum_table(thd, tables); + break; + } case SQLCOM_REPAIR: { if (check_db_used(thd,tables) || diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7cb8dfaae0d..d63a15c13a8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2555,7 +2555,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, delete_count++; } else - found_count++; + found_count++; } end_read_record(&info); free_io_cache(from); @@ -2587,3 +2587,67 @@ copy_data_between_tables(TABLE *from,TABLE *to, *deleted=delete_count; DBUG_RETURN(error > 0 ? -1 : 0); } + +int mysql_checksum_table(THD* thd, TABLE_LIST* tables) +{ + TABLE_LIST *table; + List field_list; + Item *item; + Protocol *protocol= thd->protocol; + DBUG_ENTER("mysql_admin_table"); + + field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); + item->maybe_null= 1; + field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21)); + item->maybe_null= 1; + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(-1); + + for (table = tables; table; table = table->next) + { + char table_name[NAME_LEN*2+2]; + char* db = (table->db) ? table->db : thd->db; + bool fatal_error=0; + strxmov(table_name,db ? db : "",".",table->real_name,NullS); + + table->table = open_ltable(thd, table, TL_READ_NO_INSERT); +#ifdef EMBEDDED_LIBRARY + thd->net.last_errno= 0; // these errors shouldn't get client +#endif + + protocol->prepare_for_resend(); + protocol->store(table_name, system_charset_info); + + if (!table->table) + { + protocol->store_null(); + thd->net.last_error[0]=0; + } + else + { + table->table->pos_in_table_list= table; + + if (table->table->file->table_flags() & HA_HAS_CHECKSUM) + protocol->store((ulonglong)table->table->file->checksum()); + else + protocol->store_null(); +#ifdef EMBEDDED_LIBRARY + thd->net.last_errno= 0; // these errors shouldn't get client +#endif + + close_thread_tables(thd); + table->table=0; // For query cache + } + if (protocol->write()) + goto err; + } + + send_eof(thd); + DBUG_RETURN(0); + err: + close_thread_tables(thd); // Shouldn't be needed + if (table) + table->table=0; + DBUG_RETURN(-1); +} + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c1b37bdba65..9be2b21debc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -669,7 +669,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); insert_values update delete truncate rename show describe load alter optimize preload flush reset purge begin commit rollback slave master_def master_defs - repair restore backup analyze check start + repair restore backup analyze check start checksum field_list field_list_item field_spec kill column_def key_def preload_list preload_keys select_item_list select_item values_list no_braces @@ -727,6 +727,7 @@ verb_clause: | begin | change | check + | checksum | commit | create | delete @@ -1753,6 +1754,16 @@ backup: Lex->backup_dir = $6.str; }; +checksum: + CHECKSUM_SYM table_or_tables + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_CHECKSUM; + } + table_list + {} + ; + repair: REPAIR opt_no_write_to_binlog table_or_tables { @@ -5152,7 +5163,7 @@ union_opt: ; optional_order_or_limit: - /* Empty */ {} + /* Empty */ {} | { THD *thd= YYTHD; -- cgit v1.2.1 From c1551b4c04a68699872d80b7e1b9e5a969e4ff72 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Aug 2003 18:30:43 +0200 Subject: use crc32() from bundled zlib if system zlib is unavailable sql/item_create.h: previous patch cleanup sql/item_strfunc.cc: previous patch cleanup sql/item_strfunc.h: previous patch cleanup sql/lex.h: previous patch cleanup --- include/my_sys.h | 3 ++- mysys/Makefile.am | 2 +- mysys/my_crc32.c | 36 ++++++++++++++++++++++++++++++++++++ sql/item_create.h | 2 -- sql/item_strfunc.cc | 19 +++---------------- sql/item_strfunc.h | 40 ++++++++++++++++++++-------------------- sql/lex.h | 2 -- 7 files changed, 62 insertions(+), 42 deletions(-) create mode 100644 mysys/my_crc32.c diff --git a/include/my_sys.h b/include/my_sys.h index 6721d77a8af..a6a4d46e227 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -753,8 +753,9 @@ extern my_bool my_uncompress(byte *, ulong *, ulong *); extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen); extern ha_checksum my_checksum(ha_checksum crc, const byte *mem, uint count); extern uint my_bit_log2(ulong value); -uint my_count_bits(ulonglong v); +extern uint my_count_bits(ulonglong v); extern void my_sleep(ulong m_seconds); +extern ulong crc32(ulong crc, const uchar *buf, uint len); #ifdef __WIN__ extern my_bool have_tcpip; /* Is set if tcpip is used */ diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 5b1c859cb2a..9e563755ebd 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -29,7 +29,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ mf_path.c mf_loadpath.c\ my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_pread.c my_write.c \ - mf_keycache.c \ + mf_keycache.c my_crc32.c \ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ diff --git a/mysys/my_crc32.c b/mysys/my_crc32.c new file mode 100644 index 00000000000..5514b01ede2 --- /dev/null +++ b/mysys/my_crc32.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" + +#ifndef HAVE_COMPRESS + +/* minimal set of defines for using crc32() from zlib codebase */ +#define _ZLIB_H +#define ZEXPORT +#define Z_NULL 0 +#define OF(args) args +#undef DYNAMIC_CRC_TABLE +typedef uchar Byte; +typedef uchar Bytef; +typedef uint uInt; +typedef ulong uLong; +typedef ulong uLongf; + +#include "../zlib/crc32.c" + +#endif + diff --git a/sql/item_create.h b/sql/item_create.h index 1326077b096..e80272e21a5 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -33,9 +33,7 @@ Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); Item *create_func_cot(Item* a); -#ifdef HAVE_COMPRESS Item *create_func_crc32(Item* a); -#endif Item *create_func_date_format(Item* a,Item *b); Item *create_func_dayname(Item* a); Item *create_func_dayofmonth(Item* a); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7c6e6e0686c..cb24fb0f027 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2561,9 +2561,6 @@ longlong Item_func_uncompressed_length::val_int() return uint4korr(res->c_ptr()) & 0x3FFFFFFF; } -#ifdef HAVE_COMPRESS -#include "zlib.h" - longlong Item_func_crc32::val_int() { String *res=args[0]->val_str(&value); @@ -2573,21 +2570,11 @@ longlong Item_func_crc32::val_int() return 0; /* purecov: inspected */ } null_value=0; - return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length()); + return (longlong) crc32(0L, (uchar*)res->ptr(), res->length()); } -longlong Item_func_uncompressed_length::val_int() -{ - String *res= args[0]->val_str(&value); - if (!res) - { - null_value=1; - return 0; /* purecov: inspected */ - } - null_value=0; - if (res->is_empty()) return 0; - return uint4korr(res->c_ptr()) & 0x3FFFFFFF; -} +#ifdef HAVE_COMPRESS +#include "zlib.h" String *Item_func_compress::val_str(String *str) { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index d7547d69aed..a8725febe62 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -630,6 +630,26 @@ public: }; }; +class Item_func_crc32 :public Item_int_func +{ + String value; +public: + Item_func_crc32(Item *a) :Item_int_func(a) {} + const char *func_name() const { return "crc32"; } + void fix_length_and_dec() { max_length=10; } + longlong val_int(); +}; + +class Item_func_uncompressed_length : public Item_int_func +{ + String value; +public: + Item_func_uncompressed_length(Item *a):Item_int_func(a){} + const char *func_name() const{return "uncompressed_length";} + void fix_length_and_dec() { max_length=10; } + longlong val_int(); +}; + #ifdef HAVE_COMPRESS #define ZLIB_DEPENDED_FUNCTION ; #else @@ -656,23 +676,3 @@ public: String *val_str(String *) ZLIB_DEPENDED_FUNCTION }; -class Item_func_crc32 :public Item_int_func -{ - String value; -public: - Item_func_crc32(Item *a) :Item_int_func(a) {} - const char *func_name() const { return "crc32"; } - void fix_length_and_dec() { max_length=10; } - longlong val_int() ZLIB_DEPENDED_FUNCTION -}; - -class Item_func_uncompressed_length : public Item_int_func -{ - String value; -public: - Item_func_uncompressed_length(Item *a):Item_int_func(a){} - const char *func_name() const{return "uncompressed_length";} - void fix_length_and_dec() { max_length=10; } - longlong val_int(); -}; - diff --git a/sql/lex.h b/sql/lex.h index 35c4d990b32..7ac61c73ad8 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -472,9 +472,7 @@ static SYMBOL sql_functions[] = { { "COUNT", SYM(COUNT_SYM),0,0}, { "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)}, { "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)}, -#ifdef HAVE_COMPRESS { "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)}, -#endif { "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)}, { "CURDATE", SYM(CURDATE),0,0}, { "CURTIME", SYM(CURTIME),0,0}, -- cgit v1.2.1 From 619c0d89c6a5162ec4e7cf24a61ee5d38e9300bd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Aug 2003 18:21:23 +0200 Subject: bug #1078. two innodb+delayed crashes --- mysql-test/r/innodb.result | 12 ++++++++++++ mysql-test/t/innodb.test | 14 ++++++++++++++ sql/sql_insert.cc | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 69268f1d5c5..20cc50dcc61 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1329,3 +1329,15 @@ id label 3524 Societe Test 3525 Fournisseur Test drop table t1,t2; +create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) type=innodb; +select * from t1; +c1 c2 stamp +replace delayed into t1 (c1, c2) values ( "text1","11"),( "text2","12"); +ERROR HY000: Table storage engine for 't1' doesn't have this option +select * from t1; +c1 c2 stamp +replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text3","14", "a" ),( "text4","15", "b" ); +ERROR HY000: Table storage engine for 't1' doesn't have this option +select * from t1; +c1 c2 stamp +drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 635a15baa41..cd3a5693535 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -906,3 +906,17 @@ SELECT t2.id, t1.label FROM t2 INNER JOIN (SELECT t1.id_object as id_object FROM t1 WHERE t1.label LIKE '%test%') AS lbl ON (t2.id = lbl.id_object) INNER JOIN t1 ON (t2.id = t1.id_object); drop table t1,t2; + +# +# Bug #1078 +# +create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) type=innodb; +select * from t1; +--error 1031 +replace delayed into t1 (c1, c2) values ( "text1","11"),( "text2","12"); +select * from t1; +--error 1031 +replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text3","14", "a" ),( "text4","15", "b" ); +select * from t1; +drop table t1; + diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 947205949f1..6cc5d25c34e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -172,7 +172,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, else res= (table == 0); else + { + lock_type=TL_WRITE; res= open_and_lock_tables(thd, table_list); + } } else res= open_and_lock_tables(thd, table_list); @@ -627,6 +630,7 @@ public: thd.current_tablenr=0; thd.version=refresh_version; thd.command=COM_DELAYED_INSERT; + thd.lex.current_select= 0; /* for my_message_sql */ bzero((char*) &thd.net,sizeof(thd.net)); // Safety thd.system_thread=1; -- cgit v1.2.1 From 710d4f140a3c0f292f964cc5acc93a9a96318f69 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Aug 2003 23:41:56 +0200 Subject: added support for --libs_r --- scripts/mysql_config.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index 3cc5b3a5016..e8cc9322eaf 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -86,6 +86,8 @@ client_libs='@CLIENT_LIBS@' libs="$ldflags -L'$pkglibdir' -lmysqlclient $client_libs" libs=`echo $libs | sed -e 's; +;;'` +libs_r="$ldflags -L'$pkglibdir' -lmysqlclient_r $client_libs" +libs_r=`echo $libs_r | sed -e 's; +;;'` cflags="-I'$pkgincludedir'" embedded_libs="$ldflags -L'$pkglibdir' -lmysqld @LIBS@ @innodb_system_libs@" @@ -95,6 +97,7 @@ Usage: $0 [OPTIONS] Options: --cflags [$cflags] --libs [$libs] + --libs_r [$libs_r] --socket [$socket] --port [$port] --version [$version] @@ -109,6 +112,7 @@ while test $# -gt 0; do case $1 in --cflags) echo "$cflags" ;; --libs) echo "$libs" ;; + --libs_r) echo "$libs_r" ;; --socket) echo "$socket" ;; --port) echo "$port" ;; --version) echo "$version" ;; -- cgit v1.2.1 From c64d2b6f89a8607ba6905f081eeb4416f15f7dd3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 23 Aug 2003 21:21:02 +0300 Subject: union.result: same as above sql_lex.h: same as above sql_union.cc: same as aobve sql_select.cc: Fixing that SQL_CALC_FOUND_ROWS work properly in UNION's in 4.1 Plus updating some fields in THD in the proper places plus fixing a wrong result sql/sql_select.cc: Fixing that SQL_CALC_FOUND_ROWS work properly in UNION's in 4.1 Plus updating some fields in THD in the proper places plus fixing a wrong result sql/sql_union.cc: same as aobve sql/sql_lex.h: same as above mysql-test/r/union.result: same as above --- mysql-test/r/union.result | 2 +- sql/sql_lex.h | 4 ++-- sql/sql_select.cc | 5 +++-- sql/sql_union.cc | 39 ++++++++++++++++++++++++--------------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 396eba7197b..fc72f55172b 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -103,7 +103,7 @@ a b 2 b select found_rows(); found_rows() -6 +8 explain select a,b from t1 union all select a,b from t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 506818cdcf9..593f08a4ad1 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -290,8 +290,8 @@ protected: select_result *result; int res; - bool describe, found_rows_for_union, - prepared, // prepare phase already performed for UNION (unit) + ulong describe, found_rows_for_union; + bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) executed, // already executed t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 988634fa3d6..f7e5bcf8931 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -941,6 +941,7 @@ JOIN::exec() DBUG_ENTER("JOIN::exec"); error= 0; + thd->limit_found_rows= thd->examined_row_count= 0; if (procedure) { if (procedure->change_columns(fields_list) || @@ -1323,6 +1324,8 @@ JOIN::exec() thd->proc_info="Sending data"; error= thd->net.report_error || do_select(curr_join, curr_fields_list, NULL, procedure); + thd->limit_found_rows= curr_join->send_records; + thd->examined_row_count= curr_join->examined_rows; DBUG_VOID_RETURN; } @@ -1434,8 +1437,6 @@ err: (join->tmp_join->error=join->error,join->tmp_join): join); - thd->limit_found_rows= curr_join->send_records; - thd->examined_row_count= curr_join->examined_rows; thd->proc_info="end"; err= join->cleanup(); if (thd->net.report_error) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index cfed5083b71..b065487fd4f 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -204,7 +204,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR && !sl->braces) + if (select_limit_cnt == HA_POS_ERROR || sl->braces) sl->options&= ~OPTION_FOUND_ROWS; res= join->prepare(&sl->ref_pointer_array, @@ -249,7 +249,7 @@ int st_select_lex_unit::exec() { SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; SELECT_LEX *select_cursor=first_select_in_union(); - unsigned int add_rows=0; + ulonglong add_rows=0; DBUG_ENTER("st_select_lex_unit::exec"); if (executed && !(dependent || uncacheable)) @@ -266,7 +266,7 @@ int st_select_lex_unit::exec() } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { - unsigned int rows; + ha_rows records_at_start; if (optimized) res= sl->join->reinit(); else @@ -279,12 +279,15 @@ int st_select_lex_unit::exec() select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) + if (select_limit_cnt == HA_POS_ERROR || sl->braces) sl->options&= ~OPTION_FOUND_ROWS; - else if (found_rows_for_union) + else { - rows= thd->select_limit; - sl->options|= OPTION_FOUND_ROWS; + /* + We are doing an union without braces. In this case + SQL_CALC_FOUND_ROWS should be done on all sub parts + */ + sl->options|= found_rows_for_union; } res= join->prepare(&sl->ref_pointer_array, @@ -308,6 +311,7 @@ int st_select_lex_unit::exec() } if (!res) { + records_at_start= table->file->records; sl->join->exec(); res= sl->join->error; if (!res && union_result->flush()) @@ -321,8 +325,17 @@ int st_select_lex_unit::exec() thd->lex.current_select= lex_select_save; DBUG_RETURN(res); } - if (found_rows_for_union && !sl->braces && sl->options & OPTION_FOUND_ROWS) - add_rows+= (thd->limit_found_rows > rows) ? thd->limit_found_rows - rows : 0; + if (found_rows_for_union & sl->options) + { + /* + This is a union without braces. Remember the number of rows that could + also have been part of the result set. + We get this from the difference of between total number of possible + rows and actual rows added to the temporary table. + */ + add_rows+= (ulonglong) (thd->limit_found_rows - (table->file->records - + records_at_start)); + } } } optimized= 1; @@ -360,12 +373,8 @@ int st_select_lex_unit::exec() (ORDER*) NULL, NULL, (ORDER*) NULL, thd->options | SELECT_NO_UNLOCK, result, this, fake_select, 0); - if (found_rows_for_union && !res) - { - thd->limit_found_rows= table->file->records; - if (!select_cursor->braces) - thd->limit_found_rows+= add_rows; - } + if (!res) + thd->limit_found_rows = (ulonglong)table->file->records + add_rows; fake_select->exclude(); delete fake_select; /* -- cgit v1.2.1 From 76438bd1bb07979badbd05048b7bb4a1b9fb333a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Aug 2003 17:07:14 +0300 Subject: symlink.result: Fix for a small error in the merge from 4.0 mysql-test/r/symlink.result: Fix for a small error in the merge from 4.0 --- mysql-test/r/symlink.result | 2 -- 1 file changed, 2 deletions(-) diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index 216fb4d6124..4469ca36941 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -46,8 +46,6 @@ alter table t8 rename t7; rename table t7 to t9; drop table t1; Got one of the listed errors -Warnings: -Note 1008 Can't drop database 'test_mysqltest'; database doesn't exist Got one of the listed errors Got one of the listed errors Got one of the listed errors -- cgit v1.2.1 From c01d65bce04c91c267ca851cd5a6d7b6fd796b97 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Aug 2003 17:52:54 +0300 Subject: Cleanups BTREE, HASH and RTREE are not reserved symbols anymore mysql-test/t/loaddata.test: Removed empty lines mysys/my_malloc.c: Fixed old style variable name mysys/my_realloc.c: Fixed old style variable name sql/sql_yacc.yy: BTREE, HASH and RTREE are not reserved symbols anymore sql/table.cc: Simple optimization --- mysql-test/t/loaddata.test | 4 ---- mysys/my_malloc.c | 34 +++++++++++++++++----------------- mysys/my_realloc.c | 33 +++++++++++++++++---------------- sql/sql_yacc.yy | 3 +++ sql/table.cc | 7 ++----- 5 files changed, 39 insertions(+), 42 deletions(-) diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 2f484d30ff7..199da9c4a84 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -15,7 +15,3 @@ truncate table t1; load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); SELECT * from t1; drop table t1; - - - - diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c index b273363aaf1..df9fe1f9bc4 100644 --- a/mysys/my_malloc.c +++ b/mysys/my_malloc.c @@ -24,26 +24,26 @@ /* My memory allocator */ -gptr my_malloc(unsigned int Size, myf MyFlags) +gptr my_malloc(unsigned int size, myf my_flags) { gptr point; DBUG_ENTER("my_malloc"); - DBUG_PRINT("my",("Size: %u MyFlags: %d",Size, MyFlags)); + DBUG_PRINT("my",("size: %u my_flags: %d",size, my_flags)); - if (!Size) - Size=1; /* Safety */ - if ((point = (char*)malloc(Size)) == NULL) + if (!size) + size=1; /* Safety */ + if ((point = (char*)malloc(size)) == NULL) { my_errno=errno; - if (MyFlags & MY_FAE) + if (my_flags & MY_FAE) error_handler_hook=fatal_error_handler_hook; - if (MyFlags & (MY_FAE+MY_WME)) - my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size); - if (MyFlags & MY_FAE) + if (my_flags & (MY_FAE+MY_WME)) + my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size); + if (my_flags & MY_FAE) exit(1); } - else if (MyFlags & MY_ZEROFILL) - bzero(point,Size); + else if (my_flags & MY_ZEROFILL) + bzero(point,size); DBUG_PRINT("exit",("ptr: %lx",point)); DBUG_RETURN(point); } /* my_malloc */ @@ -64,29 +64,29 @@ void my_no_flags_free(gptr ptr) /* malloc and copy */ -gptr my_memdup(const byte *from, uint length, myf MyFlags) +gptr my_memdup(const byte *from, uint length, myf my_flags) { gptr ptr; - if ((ptr=my_malloc(length,MyFlags)) != 0) + if ((ptr=my_malloc(length,my_flags)) != 0) memcpy((byte*) ptr, (byte*) from,(size_t) length); return(ptr); } -char *my_strdup(const char *from, myf MyFlags) +char *my_strdup(const char *from, myf my_flags) { gptr ptr; uint length=(uint) strlen(from)+1; - if ((ptr=my_malloc(length,MyFlags)) != 0) + if ((ptr=my_malloc(length,my_flags)) != 0) memcpy((byte*) ptr, (byte*) from,(size_t) length); return((my_string) ptr); } -char *my_strdup_with_length(const byte *from, uint length, myf MyFlags) +char *my_strdup_with_length(const byte *from, uint length, myf my_flags) { gptr ptr; - if ((ptr=my_malloc(length+1,MyFlags)) != 0) + if ((ptr=my_malloc(length+1,my_flags)) != 0) { memcpy((byte*) ptr, (byte*) from,(size_t) length); ((char*) ptr)[length]=0; diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c index 49d96c2eb4f..5190fa75dce 100644 --- a/mysys/my_realloc.c +++ b/mysys/my_realloc.c @@ -23,40 +23,41 @@ /* My memory re allocator */ -gptr my_realloc(gptr oldpoint, uint Size, myf MyFlags) +gptr my_realloc(gptr oldpoint, uint size, myf my_flags) { gptr point; DBUG_ENTER("my_realloc"); - DBUG_PRINT("my",("ptr: %lx Size: %u MyFlags: %d",oldpoint, Size, MyFlags)); + DBUG_PRINT("my",("ptr: %lx size: %u my_flags: %d",oldpoint, size, + my_flags)); - if (!oldpoint && (MyFlags & MY_ALLOW_ZERO_PTR)) - DBUG_RETURN(my_malloc(Size,MyFlags)); + if (!oldpoint && (my_flags & MY_ALLOW_ZERO_PTR)) + DBUG_RETURN(my_malloc(size,my_flags)); #ifdef USE_HALLOC - if (!(point = malloc(Size))) + if (!(point = malloc(size))) { - if (MyFlags & MY_FREE_ON_ERROR) - my_free(oldpoint,MyFlags); - if (MyFlags & MY_HOLD_ON_ERROR) + if (my_flags & MY_FREE_ON_ERROR) + my_free(oldpoint,my_flags); + if (my_flags & MY_HOLD_ON_ERROR) DBUG_RETURN(oldpoint); my_errno=errno; - if (MyFlags & MY_FAE+MY_WME) - my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size); + if (my_flags & MY_FAE+MY_WME) + my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size); } else { - memcpy(point,oldpoint,Size); + memcpy(point,oldpoint,size); free(oldpoint); } #else - if ((point = (char*)realloc(oldpoint,Size)) == NULL) + if ((point = (char*)realloc(oldpoint,size)) == NULL) { - if (MyFlags & MY_FREE_ON_ERROR) + if (my_flags & MY_FREE_ON_ERROR) my_free(oldpoint,MyFLAGS); - if (MyFlags & MY_HOLD_ON_ERROR) + if (my_flags & MY_HOLD_ON_ERROR) DBUG_RETURN(oldpoint); my_errno=errno; - if (MyFlags & (MY_FAE+MY_WME)) - my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), Size); + if (my_flags & (MY_FAE+MY_WME)) + my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), size); } #endif DBUG_PRINT("exit",("ptr: %lx",point)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 98746410470..2e66bcbb7aa 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4363,6 +4363,7 @@ keyword: | BOOL_SYM {} | BOOLEAN_SYM {} | BYTE_SYM {} + | BTREE_SYM {} | CACHE_SYM {} | CHANGED {} | CHARSET {} @@ -4408,6 +4409,7 @@ keyword: | GRANTS {} | GLOBAL_SYM {} | HANDLER_SYM {} + | HASH_SYM {} | HEAP_SYM {} | HELP_SYM {} | HOSTS_SYM {} @@ -4490,6 +4492,7 @@ keyword: | ROWS_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} + | RTREE_SYM {} | SAVEPOINT_SYM {} | SECOND_SYM {} | SERIAL_SYM {} diff --git a/sql/table.cc b/sql/table.cc index 9d12de1f6c7..a980e086d60 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1207,17 +1207,14 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res) char *get_field(MEM_ROOT *mem, Field *field) { - char buff[MAX_FIELD_WIDTH], *to; + char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff),&my_charset_bin); uint length; field->val_str(&str,&str); if (!(length= str.length())) return NullS; - to= (char*) alloc_root(mem,length+1); - memcpy(to, str.ptr(), (uint) length); - to[length]=0; - return to; + return strmake_root(mem, str.ptr(), length); } -- cgit v1.2.1 From 91dc31d38334cddc0b47c9ac0c0be338fc8cfd20 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Aug 2003 20:23:48 +0300 Subject: Fix for bug in ROLLUP when all tables where 'const' tables (Bug #714) mysql-test/r/olap.result: new test case for bug mysql-test/t/olap.test: new test case for bug sql-common/client.c: Safety fix --- mysql-test/r/olap.result | 15 +++++++++++++++ mysql-test/t/olap.test | 11 +++++++++++ sql-common/client.c | 2 +- sql/sql_select.cc | 25 +++++++++++++++---------- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 0b7a98e3fb3..84e37bf56a9 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -254,3 +254,18 @@ ERROR 42000: This version of MySQL doesn't yet support 'CUBE' select product, country_id , year, sum(profit) from t1 group by product, country_id, year with cube union all select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; ERROR 42000: This version of MySQL doesn't yet support 'CUBE' drop table t1,t2; +CREATE TABLE t1 (i int); +INSERT INTO t1 VALUES(100); +CREATE TABLE t2 (i int); +INSERT INTO t2 VALUES (100),(200); +SELECT i, COUNT(*) FROM t1 GROUP BY i WITH ROLLUP; +i COUNT(*) +100 1 +NULL 1 +SELECT t1.i, t2.i, COUNT(*) FROM t1,t2 GROUP BY t1.i,t2.i WITH ROLLUP; +i i COUNT(*) +100 100 1 +100 200 1 +100 NULL 2 +NULL NULL 2 +drop table t1,t2; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 3b1e3fac7c2..17bf6230f76 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -77,3 +77,14 @@ select product, country_id , year, sum(profit) from t1 group by product, country drop table t1,t2; +# +# Test bug with const tables +# + +CREATE TABLE t1 (i int); +INSERT INTO t1 VALUES(100); +CREATE TABLE t2 (i int); +INSERT INTO t2 VALUES (100),(200); +SELECT i, COUNT(*) FROM t1 GROUP BY i WITH ROLLUP; +SELECT t1.i, t2.i, COUNT(*) FROM t1,t2 GROUP BY t1.i,t2.i WITH ROLLUP; +drop table t1,t2; diff --git a/sql-common/client.c b/sql-common/client.c index 222f0bf0288..25b18c27d8a 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -587,7 +587,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); #ifdef MYSQL_SERVER - if (socket_errno == SOCKET_EINTR) + if (vio_errno(net->vio) == SOCKET_EINTR) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 15d6b3954ff..412e891bad1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -117,10 +117,8 @@ static Item* part_of_refkey(TABLE *form,Field *field); static uint find_shortest_key(TABLE *table, key_map usable_keys); static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, ha_rows select_limit, bool no_changes); -static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, +static int create_sort_index(THD *thd, JOIN *join, ORDER *order, ha_rows filesort_limit, ha_rows select_limit); -static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, - ha_rows select_limit); static int remove_duplicates(JOIN *join,TABLE *entry,List &fields, Item *having); static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field, @@ -916,7 +914,7 @@ JOIN::optimize() { DBUG_PRINT("info",("Sorting for group")); thd->proc_info="Sorting for group"; - if (create_sort_index(thd, &join_tab[const_tables], group_list, + if (create_sort_index(thd, this, group_list, HA_POS_ERROR, HA_POS_ERROR) || alloc_group_fields(this, group_list) || make_sum_func_list(all_fields, fields_list, 1)) @@ -931,7 +929,7 @@ JOIN::optimize() { DBUG_PRINT("info",("Sorting for order")); thd->proc_info="Sorting for order"; - if (create_sort_index(thd, &join_tab[const_tables], order, + if (create_sort_index(thd, this, order, HA_POS_ERROR, HA_POS_ERROR)) DBUG_RETURN(1); order=0; @@ -1235,7 +1233,7 @@ JOIN::exec() if (curr_join->group_list) { thd->proc_info= "Creating sort index"; - if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list, + if (create_sort_index(thd, curr_join, curr_join->group_list, HA_POS_ERROR, HA_POS_ERROR) || make_group_fields(this, curr_join)) { @@ -1416,7 +1414,7 @@ JOIN::exec() } } } - if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables], + if (create_sort_index(thd, curr_join, curr_join->group_list ? curr_join->group_list : curr_join->order, curr_join->select_limit, unit->select_limit_cnt)) @@ -6770,16 +6768,23 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ static int -create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, +create_sort_index(THD *thd, JOIN *join, ORDER *order, ha_rows filesort_limit, ha_rows select_limit) { SORT_FIELD *sortorder; uint length; ha_rows examined_rows; - TABLE *table=tab->table; - SQL_SELECT *select=tab->select; + TABLE *table; + SQL_SELECT *select; + JOIN_TAB *tab; DBUG_ENTER("create_sort_index"); + if (join->tables == join->const_tables) + DBUG_RETURN(0); // One row, no need to sort + tab= join->join_tab + join->const_tables; + table= tab->table; + select= tab->select; + if (test_if_skip_sort_order(tab,order,select_limit,0)) DBUG_RETURN(0); if (!(sortorder=make_unireg_sortorder(order,&length))) -- cgit v1.2.1 From 8a920b6133f2485ad332c0cd33d6786ff964239d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Aug 2003 15:24:52 +0300 Subject: sql_union.cc: Post merge fixes sql/sql_union.cc: Post merge fixes --- sql/sql_union.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 57fc026f4f4..ce79a3c4ad5 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -259,7 +259,7 @@ int st_select_lex_unit::exec() } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { - ha_rows rows= 0; + ha_rows records_at_start= 0; thd->lex.current_select= sl; if (optimized) -- cgit v1.2.1 From cd822e347bca8531e671ca884ac08866e122f9e5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Aug 2003 15:32:52 +0300 Subject: Merge fixes sql/sql_union.cc: Some further merge fixes --- sql/sql_union.cc | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index ce79a3c4ad5..24497589c73 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -187,34 +187,31 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { - for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) - { - JOIN *join= new JOIN(thd, sl->item_list, - sl->options | thd->options | SELECT_NO_UNLOCK, - union_result); - thd->lex.current_select= sl; - offset_limit_cnt= sl->offset_limit; - select_limit_cnt= sl->select_limit+sl->offset_limit; - if (select_limit_cnt < sl->select_limit) - select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR || sl->braces) - sl->options&= ~OPTION_FOUND_ROWS; - - res= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, sl->with_wild, - sl->where, - ((sl->braces) ? sl->order_list.elements : 0) + - sl->group_list.elements, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl, this, t_and_f); - t_and_f= 0; - if (res || thd->is_fatal_error) - goto err; - } + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR || sl->braces) + sl->options&= ~OPTION_FOUND_ROWS; + + res= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, sl->with_wild, + sl->where, + ((sl->braces) ? sl->order_list.elements : 0) + + sl->group_list.elements, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, t_and_f); + t_and_f= 0; + if (res || thd->is_fatal_error) + goto err; } item_list.empty(); -- cgit v1.2.1 From 5f8cc0998f6366c46cc20e42e4989f8f3f468f03 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Aug 2003 18:03:39 +0500 Subject: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE --- mysql-test/r/drop.result | 10 ++++++++++ mysql-test/t/drop.test | 10 ++++++++++ sql/sql_table.cc | 17 +++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 367b28e9bf7..dbb6800cb75 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -44,3 +44,13 @@ mysql test drop database mysqltest; ERROR HY000: Can't drop database 'mysqltest'; database doesn't exist +drop table t1; +flush tables with read lock; +create table t1(n int); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +unlock tables; +create table t1(n int); +show tables; +Tables_in_test +t1 +drop table t1; diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index a55cbb45fd9..78311a9dd52 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -43,3 +43,13 @@ drop database mysqltest; show databases; --error 1008 drop database mysqltest; + +# test create table and FLUSH TABLES WITH READ LOCK +drop table t1; +flush tables with read lock; +--error 1099; +create table t1(n int); +unlock tables; +create table t1(n int); +show tables; +drop table t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 37f8d0d7f4f..f33cc8fde14 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -900,6 +900,23 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_RETURN(-1); } VOID(pthread_mutex_lock(&LOCK_open)); + if (global_read_lock) + { + thd->mysys_var->current_mutex= &LOCK_open; + thd->mysys_var->current_cond= &COND_refresh; + if (thd->global_read_lock) + my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0), + table_name); + else + while (global_read_lock && ! thd->killed) + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + pthread_mutex_unlock(&thd->mysys_var->mutex); + if (error) + goto end; + } if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if (!access(path,F_OK)) -- cgit v1.2.1 From 0ee6f7fde0c5737b2a0b703b1c2755186d7d319b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Aug 2003 22:30:50 +0300 Subject: hanged UDF interface to use clear() instead of reset() BUILD/FINISH.sh: Add just_clean option (for cleanup script) scripts/mysql_fix_privilege_tables.sql: Added 'USE mysql' for easer use on windows sql/item_sum.cc: Changed UDF interface to use clear() instead of reset() sql/item_sum.h: Changed UDF interface to use clear() instead of reset() sql/slave.cc: Fixed checking of eof for slave/master protocol. (Bug #887) sql/sql_udf.cc: Changed UDF interface to use clear() instead of reset() sql/sql_udf.h: Changed UDF interface to use clear() instead of reset() sql/sql_yacc.yy: ERRORS and WARNINGS should not be reserved words sql/udf_example.cc: Changed UDF interface to use clear() instead of reset() --- BUILD/FINISH.sh | 8 ++++++-- BUILD/cleanup | 8 ++++++++ scripts/mysql_fix_privilege_tables.sql | 12 ++++++++++++ sql/item_sum.cc | 4 ++-- sql/item_sum.h | 3 ++- sql/slave.cc | 5 +++-- sql/sql_udf.cc | 11 +++++++---- sql/sql_udf.h | 25 ++++++++----------------- sql/sql_yacc.yy | 2 ++ sql/udf_example.cc | 25 +++++++++++++++++-------- 10 files changed, 67 insertions(+), 36 deletions(-) create mode 100755 BUILD/cleanup diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index 32a4efefdfb..72188b9c24b 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -23,12 +23,16 @@ autoconf || (echo \"Can't execute autoconf\" && exit 1) if [ -d gemini ] then (cd gemini && aclocal && autoheader && aclocal && automake && autoconf) -fi +fi" +if [ -z "$just_clean" ] +then +commands="$commands CFLAGS=\"$cflags\" CXX=\"$CXX\" CXXFLAGS=\"$cxxflags\" CXXLDFLAGS=\"$CXXLDFLAGS\" \ $configure" +fi -if [ -z "$just_configure" ] +if [ -z "$just_configure" -a -z "$just_clean" ] then commands="$commands diff --git a/BUILD/cleanup b/BUILD/cleanup new file mode 100755 index 00000000000..518c5722d87 --- /dev/null +++ b/BUILD/cleanup @@ -0,0 +1,8 @@ +#! /bin/sh + +path=`dirname $0` +. "$path/SETUP.sh" + +just_clean=1; + +. "$path/FINISH.sh" diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 43dc6d89481..7af97b9fad5 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -1,3 +1,15 @@ +-- This script converts any old privilege tables to privilege tables suitable +-- for MySQL 4.0. + +-- You can safely ignore all 'Duplicate column' and 'Unknown column' errors" +-- as this just means that your tables where already up to date. +-- This script is safe to run even if your tables are already up to date! + +-- On unix, you should use the mysql_fix_privilege_tables script to execute +-- this sql script. +-- On windows you should do 'mysql --force < mysql_fix_privilege_tables.sql' + +USE mysql; ALTER TABLE user type=MyISAM; ALTER TABLE db type=MyISAM; ALTER TABLE host type=MyISAM; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0d05d05f0af..4680be828c3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1353,10 +1353,10 @@ longlong Item_sum_count_distinct::val_int() #ifdef HAVE_DLOPEN -bool Item_udf_sum::reset() +bool Item_udf_sum::clear() { DBUG_ENTER("Item_udf_sum::reset"); - udf.reset(&null_value); + udf.clear(); DBUG_RETURN(0); } diff --git a/sql/item_sum.h b/sql/item_sum.h index ebb90c05215..bd946609745 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -509,7 +509,8 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } - bool reset(); + bool reset() { return 0; } /* TO BE FIXED */ + bool clear(); bool add(); void reset_field() {}; void update_field(int offset_arg) {}; diff --git a/sql/slave.cc b/sql/slave.cc index d45cf1aa8b9..d5da8325c93 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2303,9 +2303,10 @@ server_errno=%d)", return packet_error; } - if (len == 1) + /* Check if eof packet */ + if (len < 8 && mysql->net.read_pos[0] == 254) { - sql_print_error("Slave: received 0 length packet from server, apparent\ + sql_print_error("Slave: received end packet from server, apparent\ master shutdown: %s", mysql_error(mysql)); return packet_error; diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index d191550f396..99410bb34ac 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -92,10 +92,13 @@ static void init_syms(udf_func *tmp) tmp->func_deinit = dlsym(tmp->dlhandle, nm); if (tmp->type == UDFTYPE_AGGREGATE) { - (void)strmov( end, "_reset" ); - tmp->func_reset = dlsym( tmp->dlhandle, nm ); + (void)strmov( end, "_clear" ); + tmp->func_clear = dlsym( tmp->dlhandle, nm ); (void)strmov( end, "_add" ); tmp->func_add = dlsym( tmp->dlhandle, nm ); + /* Give error if _clear and _add doesn't exists */ + if (!tmp->func_clear || ! tmp->func_add) + tmp->func= 0; } } @@ -417,7 +420,7 @@ int mysql_create_function(THD *thd,udf_func *udf) u_d->func=udf->func; u_d->func_init=udf->func_init; u_d->func_deinit=udf->func_deinit; - u_d->func_reset=udf->func_reset; + u_d->func_clear=udf->func_clear; u_d->func_add=udf->func_add; /* create entry in mysql/func table */ @@ -429,7 +432,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; - restore_record(table,default_values); // Get default values for fields + restore_record(table,default_values); // Default values for fields table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info); table->field[1]->store((longlong) u_d->returns); table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info); diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 29a351ac52f..7b10b80f148 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -33,7 +33,7 @@ typedef struct st_udf_func void *func; void *func_init; void *func_deinit; - void *func_reset; + void *func_clear; void *func_add; ulong usage_count; } udf_func; @@ -49,7 +49,7 @@ class udf_handler :public Sql_alloc UDF_ARGS f_args; UDF_INIT initid; char *num_buffer; - uchar error; + uchar error, is_null; bool initialized; Item **args; @@ -57,7 +57,7 @@ class udf_handler :public Sql_alloc table_map used_tables_cache; bool const_item_cache; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), - initialized(0) + is_null(0), initialized(0) {} ~udf_handler(); const char *name() const { return u_d ? u_d->name.str : "?"; } @@ -73,7 +73,6 @@ class udf_handler :public Sql_alloc *null_value=1; return 0.0; } - uchar is_null=0; double (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= (double (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func; double tmp=func(&initid, &f_args, &is_null, &error); @@ -92,7 +91,6 @@ class udf_handler :public Sql_alloc *null_value=1; return LL(0); } - uchar is_null=0; longlong (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= (longlong (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func; longlong tmp=func(&initid, &f_args, &is_null, &error); @@ -104,22 +102,15 @@ class udf_handler :public Sql_alloc *null_value=0; return tmp; } - void reset(my_bool *null_value) + void clear() { - uchar is_null=0; - if (get_arguments()) - { - *null_value=1; - return; - } - void (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)= - (void (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func_reset; - func(&initid, &f_args, &is_null, &error); - *null_value= (my_bool) (is_null || error); + is_null= 0; + void (*func)(UDF_INIT *, uchar *, uchar *)= + (void (*)(UDF_INIT *, uchar *, uchar *)) u_d->func_clear; + func(&initid, &is_null, &error); } void add(my_bool *null_value) { - uchar is_null=0; if (get_arguments()) { *null_value=1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b0d0565d2e3..b2b4bd206c2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4409,6 +4409,7 @@ keyword: | DYNAMIC_SYM {} | END {} | ENUM {} + | ERRORS {} | ESCAPE_SYM {} | EVENTS_SYM {} | EXECUTE_SYM {} @@ -4546,6 +4547,7 @@ keyword: | USE_FRM {} | VARIABLES {} | VALUE_SYM {} + | WARNINGS {} | WORK_SYM {} | X509_SYM {} | YEAR_SYM {} diff --git a/sql/udf_example.cc b/sql/udf_example.cc index 7f4417bf8fe..ba056a9d2fd 100644 --- a/sql/udf_example.cc +++ b/sql/udf_example.cc @@ -149,6 +149,7 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null, my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message ); void avgcost_deinit( UDF_INIT* initid ); void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); +void avgcost_clear( UDF_INIT* initid, char* is_null, char *error ); void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); } @@ -902,21 +903,29 @@ avgcost_deinit( UDF_INIT* initid ) delete initid->ptr; } + +/* This is only for MySQL 4.0 compability */ void -avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message ) +avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message) { - struct avgcost_data* data = (struct avgcost_data*)initid->ptr; - data->totalprice = 0.0; - data->totalquantity = 0; - data->count = 0; + avgcost_clear(initid, is_null, message); + avgcost_add(initid, args, is_null, message); +} - *is_null = 0; - avgcost_add( initid, args, is_null, message ); +/* This is needed to get things to work in MySQL 4.1.1 and above */ + +void +avgcost_clear(UDF_INIT* initid, char* is_null, char* message) +{ + struct avgcost_data* data = (struct avgcost_data*)initid->ptr; + data->totalprice= 0.0; + data->totalquantity= 0; + data->count= 0; } void -avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message ) +avgcost_add(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message) { if (args->args[0] && args->args[1]) { -- cgit v1.2.1 From a73058a77c0fe693ea825ab5f9b896fd7eb1bc2c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Aug 2003 19:11:54 -0400 Subject: fixed bug #910 (right type of ifnull function) mysql-test/r/create.result: added test for bug #910 (right type of ifnull function) mysql-test/t/create.test: added test for bug #910 (right type of ifnull function) sql/field.h: added new constructors of Field_decimal, Field_tiny, Field_short, Field_float, Field_null, Field_year for using in Item::tmp_table_field_from_field_type sql/item.cc: added Item::tmp_table_field_from_field_type sql/item.h: added Item::tmp_table_field_from_field_type --- mysql-test/r/create.result | 49 +++++++++++++++++++++++++++++++++ mysql-test/t/create.test | 38 ++++++++++++++++++++++++++ sql/field.h | 29 ++++++++++++++++++++ sql/item.cc | 67 ++++++++++++++++++++++++++++++++++++++++++++++ sql/item.h | 2 ++ sql/item_cmpfunc.cc | 13 +++++++++ sql/item_cmpfunc.h | 4 +++ 7 files changed, 202 insertions(+) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 9a0eca52b84..5567cc7c841 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -310,3 +310,52 @@ t1 CREATE TABLE `t1` ( ) TYPE=MyISAM CHARSET=latin1 SET SESSION table_type=default; drop table t1; +create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); +insert into t1(a)values(1); +insert into t1(a,b,c,d,e,f,g,h) +values(2,-2,2,'1825-12-14','a','2003-1-1 3:2:1','4:3:2','binary data'); +select * from t1; +a b c d e f g h +1 NULL NULL NULL NULL NULL NULL NULL +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data +select a, +ifnull(b,cast(-7 as signed)) as b, +ifnull(c,cast(7 as unsigned)) as c, +ifnull(d,cast('2000-01-01' as date)) as d, +ifnull(e,cast('b' as char)) as e, +ifnull(f,cast('2000-01-01' as datetime)) as f, +ifnull(g,cast('5:4:3' as time)) as g, +ifnull(h,cast('yet another binary data' as binary)) as h, +addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +a b c d e f g h dd +1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 +create table t2 +select +a, +ifnull(b,cast(-7 as signed)) as b, +ifnull(c,cast(7 as unsigned)) as c, +ifnull(d,cast('2000-01-01' as date)) as d, +ifnull(e,cast('b' as char)) as e, +ifnull(f,cast('2000-01-01' as datetime)) as f, +ifnull(g,cast('5:4:3' as time)) as g, +ifnull(h,cast('yet another binary data' as binary)) as h, +addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +explain t2; +Field Type Null Key Default Extra +a int(11) YES NULL +b bigint(11) 0 +c bigint(10) 0 +d date 0000-00-00 +e char(1) +f datetime 0000-00-00 00:00:00 +g time 00:00:00 +h mediumblob +dd time 00:00:00 +select * from t2; +a b c d e f g h dd +1 -7 7 2000-01-01 b 2000-01-01 00:00:00 05:04:03 yet another binary data 02:00:00 +2 -2 2 1825-12-14 a 2003-01-01 03:02:01 04:03:02 binary data 02:00:00 +drop table t1, t2; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 9bc37a0864d..b89cf854ffb 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -215,3 +215,41 @@ CREATE TABLE t1 (a int not null); show create table t1; SET SESSION table_type=default; drop table t1; + +# +# Test types of data for create select with functions +# + +create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); +insert into t1(a)values(1); +insert into t1(a,b,c,d,e,f,g,h) +values(2,-2,2,'1825-12-14','a','2003-1-1 3:2:1','4:3:2','binary data'); +select * from t1; +select a, + ifnull(b,cast(-7 as signed)) as b, + ifnull(c,cast(7 as unsigned)) as c, + ifnull(d,cast('2000-01-01' as date)) as d, + ifnull(e,cast('b' as char)) as e, + ifnull(f,cast('2000-01-01' as datetime)) as f, + ifnull(g,cast('5:4:3' as time)) as g, + ifnull(h,cast('yet another binary data' as binary)) as h, + addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; + +create table t2 +select + a, + ifnull(b,cast(-7 as signed)) as b, + ifnull(c,cast(7 as unsigned)) as c, + ifnull(d,cast('2000-01-01' as date)) as d, + ifnull(e,cast('b' as char)) as e, + ifnull(f,cast('2000-01-01' as datetime)) as f, + ifnull(g,cast('5:4:3' as time)) as g, + ifnull(h,cast('yet another binary data' as binary)) as h, + addtime(cast('1:0:0' as time),cast('1:0:0' as time)) as dd +from t1; +explain t2; + +select * from t2; + +drop table t1, t2; diff --git a/sql/field.h b/sql/field.h index 79c45a99a43..a69178b4c92 100644 --- a/sql/field.h +++ b/sql/field.h @@ -305,6 +305,11 @@ public: unireg_check_arg, field_name_arg, table_arg, dec_arg, zero_arg,unsigned_arg) {} + Field_decimal(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } @@ -334,6 +339,11 @@ public: unireg_check_arg, field_name_arg, table_arg, 0, zero_arg,unsigned_arg) {} + Field_tiny(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum Item_result result_type () const { return INT_RESULT; } enum_field_types type() const { return FIELD_TYPE_TINY;} enum ha_base_keytype key_type() const @@ -364,6 +374,11 @@ public: unireg_check_arg, field_name_arg, table_arg, 0, zero_arg,unsigned_arg) {} + Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg,bool unsigned_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, table_arg,0,0,unsigned_arg) + {} enum Item_result result_type () const { return INT_RESULT; } enum_field_types type() const { return FIELD_TYPE_SHORT;} enum ha_base_keytype key_type() const @@ -497,6 +512,11 @@ public: unireg_check_arg, field_name_arg, table_arg, dec_arg, zero_arg,unsigned_arg) {} + Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg, uint8 dec_arg) + :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg,dec_arg,0,0) + {} enum_field_types type() const { return FIELD_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } int store(const char *to,uint length,CHARSET_INFO *charset); @@ -558,6 +578,11 @@ public: :Field_str(ptr_arg, len_arg, null, 1, unireg_check_arg, field_name_arg, table_arg, cs) {} + Field_null(uint32 len_arg, const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_str((char*) 0, len_arg, null, 1, + NONE, field_name_arg, table_arg, cs) + {} enum_field_types type() const { return FIELD_TYPE_NULL;} int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; } int store(double nr) { null[0]=1; return 0; } @@ -627,6 +652,10 @@ public: :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, 1, 1) {} + Field_year(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg) + :Field_tiny(len_arg,maybe_null_arg,field_name_arg,table_arg,1) + {} enum_field_types type() const { return FIELD_TYPE_YEAR;} int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/item.cc b/sql/item.cc index 17b0519b61c..29f76ecff94 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -983,6 +983,73 @@ enum_field_types Item::field_type() const FIELD_TYPE_DOUBLE); } +Field *Item::tmp_table_field_from_field_type(TABLE *table) +{ + switch (field_type()) + { + case MYSQL_TYPE_DECIMAL: + return new Field_decimal(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_TINY: + return new Field_tiny(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_SHORT: + return new Field_short(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_LONG: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_FLOAT: + return new Field_float(max_length, maybe_null, name, table, decimals); + case MYSQL_TYPE_DOUBLE: + return new Field_double(max_length, maybe_null, name, table, decimals); + case MYSQL_TYPE_NULL: + return new Field_null(max_length, name, table, &my_charset_bin); +#ifdef HAVE_LONG_LONG + case MYSQL_TYPE_LONGLONG: + return new Field_longlong(max_length, maybe_null, name, table, + unsigned_flag); +#endif + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_INT24: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_DATE: + return new Field_date(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_TIME: + return new Field_time(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + return new Field_datetime(maybe_null, name, table, &my_charset_bin); + case MYSQL_TYPE_YEAR: + return new Field_year(max_length, maybe_null, name, table); + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + return new Field_long(max_length, maybe_null, name, table, + unsigned_flag); + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + case MYSQL_TYPE_VAR_STRING: + if (max_length > 255) + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + else + return new Field_varstring(max_length, maybe_null, name, table, collation.collation); + case MYSQL_TYPE_STRING: + if (max_length > 255) + return new Field_blob(max_length, maybe_null, name, table, collation.collation); + else + return new Field_string(max_length, maybe_null, name, table, collation.collation); + default: + // This case should never be choosen + DBUG_ASSERT(0); + return 0; + } +} + /* ARGSUSED */ void Item_field::make_field(Send_field *tmp_field) { diff --git a/sql/item.h b/sql/item.h index 621dc017d25..13ebe8c6cf8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -180,6 +180,8 @@ public: virtual bool null_inside() { return 0; } // used in row subselects to get value of elements virtual void bring_value() {} + + Field *tmp_table_field_from_field_type(TABLE *table); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7d8da16338b..6ec84704fca 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -687,8 +687,21 @@ Item_func_ifnull::fix_length_and_dec() agg_arg_collations(collation, args, arg_count); else if (cached_result_type != REAL_RESULT) decimals= 0; + + cached_field_type= args[0]->field_type(); + if (cached_field_type != args[1]->field_type()) + cached_field_type= Item_func::field_type(); +} + +enum_field_types Item_func_ifnull::field_type() const +{ + return cached_field_type; } +Field *Item_func_ifnull::tmp_table_field(TABLE *table) +{ + return tmp_table_field_from_field_type(table); +} double Item_func_ifnull::val() diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 25cc97d60bf..5dd919c984b 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -281,6 +281,8 @@ public: class Item_func_ifnull :public Item_func { enum Item_result cached_result_type; + enum_field_types cached_field_type; + bool field_type_defined; public: Item_func_ifnull(Item *a,Item *b) :Item_func(a,b), cached_result_type(INT_RESULT) @@ -289,8 +291,10 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } + enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } + Field *tmp_table_field(TABLE *table); }; -- cgit v1.2.1 From 85f7a6978bced6b17940363b792e7bc80dcce3aa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 03:10:14 +0300 Subject: reset() split in 2 function clear() & add() aggregate function reinitialization (if no rows was found) made with help of clear() (fixed BUG#860) mysql-test/r/subselect.result: test for BUG#860 mysql-test/t/subselect.test: test for BUG#860 sql/item_sum.cc: reset() replaced with clear() sql/item_sum.h: reset() replaced with clear() (reset now is just composition of clear() and add()) sql/item_uniq.h: reset() replaced with clear() sql/sql_select.cc: removed NULL value assigment, now it will be done by clear() call function for clearing if there was not found any row in group sql/sql_select.h: function for clearing if there was not found any row in group --- mysql-test/r/subselect.result | 9 +++++++++ mysql-test/t/subselect.test | 10 ++++++++++ sql/item_sum.cc | 31 ++++++++++++------------------- sql/item_sum.h | 29 ++++++++++++++--------------- sql/item_uniq.h | 2 +- sql/sql_select.cc | 32 ++++++++++++++++++++++---------- sql/sql_select.h | 1 + 7 files changed, 69 insertions(+), 45 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index cf02eda9aba..dd8aeba8563 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1352,3 +1352,12 @@ ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_ select * from t1 where s1 > any (select max(s2) from t1); ERROR HY000: Illegal mix of collations (latin1_german1_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation '>' drop table t1; +create table t1(toid int,rd int); +create table t2(userid int,pmnew int,pmtotal int); +insert into t2 values(1,0,0),(2,0,0); +insert into t1 values(1,0),(1,0),(1,0),(1,12),(1,15),(1,123),(1,12312),(1,12312),(1,123),(2,0),(2,0),(2,1),(2,2); +select userid,pmtotal,pmnew, (select count(rd) from t1 where toid=t2.userid) calc_total, (select count(rd) from t1 where rd=0 and toid=t2.userid) calc_new from t2 where userid in (select distinct toid from t1); +userid pmtotal pmnew calc_total calc_new +1 0 0 9 3 +2 0 0 4 2 +drop table t1, t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 457b64a5a11..c9dba498428 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -912,3 +912,13 @@ select * from t1 where s1 > (select max(s2) from t1); -- error 1266 select * from t1 where s1 > any (select max(s2) from t1); drop table t1; + +# +# aggregate functions reinitialization +# +create table t1(toid int,rd int); +create table t2(userid int,pmnew int,pmtotal int); +insert into t2 values(1,0,0),(2,0,0); +insert into t1 values(1,0),(1,0),(1,0),(1,12),(1,15),(1,123),(1,12312),(1,12312),(1,123),(2,0),(2,0),(2,1),(2,2); +select userid,pmtotal,pmnew, (select count(rd) from t1 where toid=t2.userid) calc_total, (select count(rd) from t1 where rd=0 and toid=t2.userid) calc_new from t2 where userid in (select distinct toid from t1); +drop table t1, t2; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4680be828c3..c429346a2e6 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -223,10 +223,9 @@ Item *Item_sum_sum::copy_or_same(THD* thd) } -bool Item_sum_sum::reset() +void Item_sum_sum::clear() { null_value=1; sum=0.0; - return Item_sum_sum::add(); } @@ -251,10 +250,9 @@ Item *Item_sum_count::copy_or_same(THD* thd) } -bool Item_sum_count::reset() +void Item_sum_count::clear() { - count=0; - return add(); + count= 0; } @@ -286,10 +284,9 @@ Item *Item_sum_avg::copy_or_same(THD* thd) } -bool Item_sum_avg::reset() +void Item_sum_avg::clear() { sum=0.0; count=0; - return Item_sum_avg::add(); } @@ -342,11 +339,10 @@ Item *Item_sum_variance::copy_or_same(THD* thd) } -bool Item_sum_variance::reset() +void Item_sum_variance::clear() { sum=sum_sqr=0.0; count=0; - return Item_sum_variance::add(); } bool Item_sum_variance::add() @@ -592,10 +588,9 @@ longlong Item_sum_bit::val_int() } -bool Item_sum_bit::reset() +void Item_sum_bit::clear() { - bits=reset_bits; - return add(); + bits= reset_bits; } Item *Item_sum_or::copy_or_same(THD* thd) @@ -1280,7 +1275,7 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd) } -bool Item_sum_count_distinct::reset() +void Item_sum_count_distinct::clear() { if (use_tree) reset_tree(tree); @@ -1290,7 +1285,6 @@ bool Item_sum_count_distinct::reset() table->file->delete_all_rows(); table->file->extra(HA_EXTRA_WRITE_CACHE); } - return add(); } bool Item_sum_count_distinct::add() @@ -1353,11 +1347,11 @@ longlong Item_sum_count_distinct::val_int() #ifdef HAVE_DLOPEN -bool Item_udf_sum::clear() +void Item_udf_sum::clear() { - DBUG_ENTER("Item_udf_sum::reset"); + DBUG_ENTER("Item_udf_sum::clear"); udf.clear(); - DBUG_RETURN(0); + DBUG_VOID_RETURN; } bool Item_udf_sum::add() @@ -1685,7 +1679,7 @@ Item *Item_func_group_concat::copy_or_same(THD* thd) } -bool Item_func_group_concat::reset() +void Item_func_group_concat::clear() { result.length(0); result.copy(); @@ -1699,7 +1693,6 @@ bool Item_func_group_concat::reset() } if (tree_mode) reset_tree(tree); - return add(); } diff --git a/sql/item_sum.h b/sql/item_sum.h index bd946609745..8ceada278b8 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -62,7 +62,8 @@ public: enum Type type() const { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; - virtual bool reset()=0; + inline bool reset() { clear(); return add(); }; + virtual void clear()= 0; virtual bool add()=0; virtual void reset_field()=0; virtual void update_field(int offset)=0; @@ -124,7 +125,7 @@ class Item_sum_sum :public Item_sum_num Item_sum_sum(THD *thd, Item_sum_sum &item) :Item_sum_num(thd, item), sum(item.sum) {} enum Sumfunctype sum_func () const {return SUM_FUNC;} - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -151,7 +152,7 @@ class Item_sum_count :public Item_sum_int table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_FUNC; } - bool reset(); + void clear(); void no_rows_in_result() { count=0; } bool add(); void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; } @@ -225,7 +226,7 @@ class Item_sum_count_distinct :public Item_sum_int table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } - bool reset(); + void clear(); bool add(); longlong val_int(); void reset_field() { return ;} // Never called @@ -269,7 +270,7 @@ class Item_sum_avg :public Item_sum_num Item_sum_avg(THD *thd, Item_sum_avg &item) :Item_sum_num(thd, item), sum(item.sum), count(item.count) {} enum Sumfunctype sum_func () const {return AVG_FUNC;} - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -322,7 +323,7 @@ class Item_sum_variance : public Item_sum_num Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr), count(item.count) {} enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } - bool reset(); + void clear(); bool add(); double val(); void reset_field(); @@ -391,13 +392,12 @@ class Item_sum_hybrid :public Item_sum table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } - bool reset() + void clear() { sum=0.0; sum_int=0; value.length(0); null_value=1; - return add(); } double val(); longlong val_int(); @@ -451,7 +451,7 @@ class Item_sum_bit :public Item_sum_int Item_sum_bit(THD *thd, Item_sum_bit &item): Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {} enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} - bool reset(); + void clear(); longlong val_int(); void reset_field(); void fix_length_and_dec() @@ -509,8 +509,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } - bool reset() { return 0; } /* TO BE FIXED */ - bool clear(); + void clear(); bool add(); void reset_field() {}; void update_field(int offset_arg) {}; @@ -592,7 +591,7 @@ class Item_sum_udf_float :public Item_sum_num ~Item_sum_udf_float() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val() { return 0.0; } - bool reset() { return 0; } + bool clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -609,7 +608,7 @@ public: enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { return 0; } double val() { return 0; } - bool reset() { return 0; } + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -629,7 +628,7 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { maybe_null=1; max_length=0; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } - bool reset() { return 0; } + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; @@ -715,7 +714,7 @@ class Item_func_group_concat : public Item_sum const char *func_name() const { return "group_concat"; } enum Type type() const { return SUM_FUNC_ITEM; } virtual Item_result result_type () const { return STRING_RESULT; } - bool reset(); + void clear(); bool add(); void reset_field(); bool fix_fields(THD *, TABLE_LIST *, Item **); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index f2c64c4bde9..e41397dac44 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -41,7 +41,7 @@ public: :Item_sum_num(thd, item) {} double val() { return 0.0; } enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;} - bool reset() { return 0;} + void clear() {} bool add() { return 0; } void reset_field() {} void update_field(int offset) {} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e6e7abf14a0..37454d93b6d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1003,12 +1003,6 @@ JOIN::reinit() /* Reset of sum functions */ first_record= 0; - if (sum_funcs) - { - Item_sum *func, **func_ptr= sum_funcs; - while ((func= *(func_ptr++))) - func->null_value= 1; - } if (exec_tmp_table1) { @@ -5979,8 +5973,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!join->first_record) { /* No matching rows for group function */ - clear_tables(join); - copy_fields(&join->tmp_table_param); + join->clear(); } if (join->having && join->having->val_int() == 0) error= -1; // Didn't satisfy having @@ -6246,8 +6239,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!join->first_record) { /* No matching rows for group function */ - clear_tables(join); - copy_fields(&join->tmp_table_param); + join->clear(); } copy_sum_funcs(join->sum_funcs); if (!join->having || join->having->val_int()) @@ -8542,6 +8534,26 @@ int JOIN::rollup_send_data(uint idx) return 0; } +/* + clear results if there are not rows found for group + (end_send_group/end_write_group) + + SYNOPSYS + JOIN::clear() +*/ + +void JOIN::clear() +{ + clear_tables(this); + copy_fields(&tmp_table_param); + + if (sum_funcs) + { + Item_sum *func, **func_ptr= sum_funcs; + while ((func= *(func_ptr++))) + func->clear(); + } +} /**************************************************************************** EXPLAIN handling diff --git a/sql/sql_select.h b/sql/sql_select.h index 208eaaea7bd..9ca46a505aa 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -279,6 +279,7 @@ class JOIN :public Sql_alloc Item_sum ***func); int rollup_send_data(uint idx); bool test_in_subselect(Item **where); + void clear(); }; -- cgit v1.2.1 From 36636e82786886bb4c41ec2e9cf3fb27ef42511f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 13:39:46 +0500 Subject: SCRUM: Fixed some mess with STDCALL in function's declarations include/mysql.h: That definitions are more correct libmysqld/lib_sql.cc: should be declared as STDCALL libmysqld/libmysqld.c: should be declared as STDCALL sql-common/client.c: should be declared as STDCALL --- include/mysql.h | 10 +++++----- libmysqld/lib_sql.cc | 2 +- libmysqld/libmysqld.c | 4 ++-- sql-common/client.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 8e8ffc2b788..d58b729bfc1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -541,16 +541,16 @@ typedef struct st_mysql_stmt typedef struct st_mysql_methods { - my_bool STDCALL (*read_query_result)(MYSQL *mysql); - my_bool STDCALL (*advanced_command)(MYSQL *mysql, + my_bool (STDCALL *read_query_result)(MYSQL *mysql); + my_bool (STDCALL *advanced_command)(MYSQL *mysql, enum enum_server_command command, const char *header, unsigned long header_length, const char *arg, unsigned long arg_length, my_bool skip_check); - MYSQL_RES * STDCALL (*store_result)(MYSQL *mysql); - MYSQL_RES * STDCALL (*use_result)(MYSQL *mysql); - void STDCALL (*fetch_lengths)(unsigned long *to, MYSQL_ROW column, uint field_count); + MYSQL_RES * (STDCALL *store_result)(MYSQL *mysql); + MYSQL_RES * (STDCALL *use_result)(MYSQL *mysql); + void (STDCALL *fetch_lengths)(unsigned long *to, MYSQL_ROW column, uint field_count); } MYSQL_METHODS; MYSQL_STMT * STDCALL mysql_prepare(MYSQL * mysql, const char *query, diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index aaa31908360..05c36f353fd 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -48,7 +48,7 @@ static bool check_user(THD *thd, enum_server_command command, char * get_mysql_home(){ return mysql_home;}; char * get_mysql_real_data_home(){ return mysql_real_data_home;}; -my_bool +my_bool STDCALL emb_advanced_command(MYSQL *mysql, enum enum_server_command command, const char *header, ulong header_length, const char *arg, ulong arg_length, my_bool skip_check) diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 357c13c5826..48b3397ee7c 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -59,7 +59,7 @@ #endif void free_old_query(MYSQL *mysql); -my_bool +my_bool STDCALL emb_advanced_command(MYSQL *mysql, enum enum_server_command command, const char *header, ulong header_length, const char *arg, ulong arg_length, my_bool skip_check); @@ -169,7 +169,7 @@ static inline int mysql_init_charset(MYSQL *mysql) else the lengths are calculated from the offset between pointers. **************************************************************************/ -static void emb_fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count) +static void STDCALL emb_fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count) { MYSQL_ROW end; diff --git a/sql-common/client.c b/sql-common/client.c index 25b18c27d8a..e410330d616 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -636,7 +636,7 @@ void free_rows(MYSQL_DATA *cur) } } -static my_bool +static my_bool STDCALL cli_advanced_command(MYSQL *mysql, enum enum_server_command command, const char *header, ulong header_length, const char *arg, ulong arg_length, my_bool skip_check) @@ -1008,7 +1008,7 @@ void mysql_read_default_options(struct st_mysql_options *options, else the lengths are calculated from the offset between pointers. **************************************************************************/ -static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count) +static void STDCALL cli_fetch_lengths(ulong *to, MYSQL_ROW column, uint field_count) { ulong *prev_length; byte *start=0; -- cgit v1.2.1 From 834cfbd190649b97f1c017ad107a6a335d335cb3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 13:21:30 +0300 Subject: enum renamed (asked for compilation under windows) --- sql/item_subselect.cc | 34 +++++++++++++++++----------------- sql/item_subselect.h | 2 +- sql/sql_select.cc | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index cbda995504c..d383bf65c88 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -72,7 +72,7 @@ Item_subselect::trans_res Item_subselect::select_transformer(JOIN *join) { DBUG_ENTER("Item_subselect::select_transformer"); - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } @@ -214,14 +214,14 @@ Item_singlerow_subselect::select_transformer(JOIN *join) cond= join->having; else if (!(cond= new Item_cond_and(join->conds, join->having))) - return ERROR; + return RES_ERROR; if (!(substitution= new Item_func_if(cond, substitution, new Item_null()))) - return ERROR; + return RES_ERROR; } - return REDUCE; + return RES_REDUCE; } - return OK; + return RES_OK; } void Item_singlerow_subselect::store(uint i, Item *item) @@ -508,7 +508,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { thd->lex.current_select= current; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } thd->lex.current_select= current; @@ -528,7 +528,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (select_lex->item_list.elements > 1) { my_error(ER_CARDINALITY_COL, MYF(0), 1); - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } item= (Item*) select_lex->item_list.head(); @@ -546,7 +546,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -570,7 +570,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; item= new Item_cond_or(item, @@ -578,7 +578,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, } join->conds= and_items(join->conds, item); if (join->conds->fix_fields(thd, join->tables_list, &join->conds)) - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } else { @@ -592,7 +592,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -610,11 +610,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SELECT_REDUCED, warn_buff); } - DBUG_RETURN(REDUCE); + DBUG_RETURN(RES_REDUCE); } } } - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } Item_subselect::trans_res @@ -640,7 +640,7 @@ Item_in_subselect::row_value_transformer(JOIN *join, if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { thd->lex.current_select= current; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } thd->lex.current_select= current; @@ -679,7 +679,7 @@ Item_in_subselect::row_value_transformer(JOIN *join, if (join->having->fix_fields(thd, join->tables_list, &join->having)) { select_lex->having_fix_field= 0; - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } select_lex->having_fix_field= 0; } @@ -687,9 +687,9 @@ Item_in_subselect::row_value_transformer(JOIN *join, { join->conds= and_items(join->conds, item); if (join->conds->fix_fields(thd, join->tables_list, &join->having)) - DBUG_RETURN(ERROR); + DBUG_RETURN(RES_ERROR); } - DBUG_RETURN(OK); + DBUG_RETURN(RES_OK); } Item_subselect::trans_res diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ddb53ab616a..174e8809688 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -51,7 +51,7 @@ public: /* changed engine indicator */ bool engine_changed; - enum trans_res {OK, REDUCE, ERROR}; + enum trans_res {RES_OK, RES_REDUCE, RES_ERROR}; enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, EXISTS_SUBS, IN_SUBS, ALLANY_SUBS}; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e6e7abf14a0..afcdb7617ec 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -324,8 +324,8 @@ JOIN::prepare(Item ***rref_pointer_array, { Item_subselect::trans_res res; if ((res= subselect->select_transformer(this)) != - Item_subselect::OK) - DBUG_RETURN((res == Item_subselect::ERROR)); + Item_subselect::RES_OK) + DBUG_RETURN((res == Item_subselect::RES_ERROR)); } } -- cgit v1.2.1 From 241ed6b81caf0248200aacbd7e945a24ce835baa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 18:09:00 +0500 Subject: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE This commit is related to my previos one(ChangeSet 1.1583 03/08/27 18:03:39). Note about COMMIT&ROLLBACK: Only 'COMMIT' statement updates the binary log. 'ROLLBACK' statement doesn't update the binlog. mysql-test/r/drop.result: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE mysql-test/r/innodb.result: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE mysql-test/t/drop.test: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE mysql-test/t/innodb.test: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE sql/handler.cc: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE sql/sql_table.cc: Fix for bug #799 FLUSH TABLES WITH READ LOCK does not block CREATE TABLE --- mysql-test/r/drop.result | 2 +- mysql-test/r/innodb.result | 12 ++++++++++++ mysql-test/t/drop.test | 2 +- mysql-test/t/innodb.test | 15 +++++++++++++++ sql/handler.cc | 3 +++ sql/sql_table.cc | 28 +++++++--------------------- 6 files changed, 39 insertions(+), 23 deletions(-) diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index dbb6800cb75..3748af1b8f9 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -47,7 +47,7 @@ ERROR HY000: Can't drop database 'mysqltest'; database doesn't exist drop table t1; flush tables with read lock; create table t1(n int); -ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +ERROR HY000: Can't execute the query because you have a conflicting read lock unlock tables; create table t1(n int); show tables; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 8592393fd42..36bc1c814e4 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -251,6 +251,18 @@ n 6 rollback; drop table t1; +create table t1 (n int not null primary key) type=innodb; +start transaction; +insert into t1 values (4); +flush tables with read lock; +commit; +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +commit; +select * from t1; +n +4 +drop table t1; create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) type=innodb; begin; insert into t1 values(1,'hamdouni'); diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test index 78311a9dd52..43329a849f8 100644 --- a/mysql-test/t/drop.test +++ b/mysql-test/t/drop.test @@ -47,7 +47,7 @@ drop database mysqltest; # test create table and FLUSH TABLES WITH READ LOCK drop table t1; flush tables with read lock; ---error 1099; +--error 1223; create table t1(n int); unlock tables; create table t1(n int); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 6e7eb0ea06f..870fc8cc2b0 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -133,6 +133,21 @@ select n from t1; rollback; drop table t1; +# +# Test for commit and FLUSH TABLES WITH READ LOCK +# + +create table t1 (n int not null primary key) type=innodb; +start transaction; +insert into t1 values (4); +flush tables with read lock; +--error 1223; +commit; +unlock tables; +commit; +select * from t1; +drop table t1; + # # Testing transactions # diff --git a/sql/handler.cc b/sql/handler.cc index b4d370491bb..851e73f15d2 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -359,7 +359,10 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { + if (wait_if_global_read_lock(thd, 0)) + DBUG_RETURN(1); mysql_bin_log.write(thd, &thd->transaction.trans_log); + start_waiting_global_read_lock(thd); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); thd->transaction.trans_log.end_of_file= max_binlog_cache_size; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f33cc8fde14..006cec7000f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -899,33 +899,18 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); DBUG_RETURN(-1); } + if (wait_if_global_read_lock(thd, 0)) + DBUG_RETURN(error); VOID(pthread_mutex_lock(&LOCK_open)); - if (global_read_lock) - { - thd->mysys_var->current_mutex= &LOCK_open; - thd->mysys_var->current_cond= &COND_refresh; - if (thd->global_read_lock) - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0), - table_name); - else - while (global_read_lock && ! thd->killed) - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - pthread_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - if (error) - goto end; - } if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if (!access(path,F_OK)) { - VOID(pthread_mutex_unlock(&LOCK_open)); if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - DBUG_RETURN(0); - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); - DBUG_RETURN(-1); + error= 0; + else + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto end; } } @@ -963,6 +948,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, error=0; end: VOID(pthread_mutex_unlock(&LOCK_open)); + start_waiting_global_read_lock(thd); thd->proc_info="After create"; DBUG_RETURN(error); } -- cgit v1.2.1 From f8e55811316ada1a24de26493ae38bdf8a312f22 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 10:26:56 -0400 Subject: fixed merge mistake --- mysql-test/r/create.result | 1 - mysql-test/t/create.test | 2 -- 2 files changed, 3 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index be35bda3b6c..80ff8aef15b 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -310,7 +310,6 @@ t1 CREATE TABLE `t1` ( ) TYPE=MyISAM CHARSET=latin1 SET SESSION table_type=default; drop table t1; -drop table t1; create table t1 select x'4132'; drop table t1; create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index fee3e796805..2e21768dc0b 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -216,8 +216,6 @@ show create table t1; SET SESSION table_type=default; drop table t1; -drop table t1; - # # Bug # 801 # -- cgit v1.2.1 From 38a65b4d4e1767b55f0f578ef28d6c353b3c547a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 19:27:46 +0500 Subject: Fix for the bug #1125 mysqldump -X creates invalid XML --- client/mysqldump.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index b317c7e5d13..feaaaccd01d 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1137,7 +1137,7 @@ static void dumpTable(uint numFields, char *table) safe_exit(EX_CONSCHECK); return; } - if (extended_insert) + if (extended_insert && !opt_xml) { ulong length = lengths[i]; if (i == 0) @@ -1222,7 +1222,7 @@ static void dumpTable(uint numFields, char *table) if (opt_xml) fprintf(md_result_file, "\t\n"); - if (extended_insert) + if (extended_insert && !opt_xml) { ulong row_length; dynstr_append(&extended_row,")"); @@ -1404,7 +1404,7 @@ static int init_dumping(char *database) (opt_quoted ? "`" : "")); } } - if (extended_insert) + if (extended_insert && !opt_xml) if (init_dynamic_string(&extended_row, "", 1024, 1024)) exit(EX_EOM); return 0; @@ -1676,7 +1676,7 @@ int main(int argc, char **argv) if (md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - if (extended_insert) + if (extended_insert & !opt_xml) dynstr_free(&extended_row); my_end(0); return(first_error); -- cgit v1.2.1 From 0f57bb2eda7b76f7a5e8bb34b6f01084d84ab6d1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Aug 2003 18:31:38 +0300 Subject: fixed typo --- sql/item_sum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_sum.h b/sql/item_sum.h index 8ceada278b8..e9f9890f41d 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -591,7 +591,7 @@ class Item_sum_udf_float :public Item_sum_num ~Item_sum_udf_float() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val() { return 0.0; } - bool clear() {} + void clear() {} bool add() { return 0; } void update_field(int offset) {} }; -- cgit v1.2.1 From 40156410f9d26e3d649d71aa2a005c5f933fa6e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Aug 2003 02:28:32 +0600 Subject: BUG correct bugs #833 and #836 sql/item_sum.cc: correct bug #833 (add real_item()) sql/item_sum.h: correct bug #836 add method no_rows_in_result() --- sql/item_sum.cc | 8 ++++---- sql/item_sum.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4680be828c3..be2b419dcd4 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1466,7 +1466,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1, for (uint i= 0; i < item->arg_count_field; i++) { Item *field_item= item->args[i]; - Field *field= field_item->tmp_table_field(); + Field *field= field_item->real_item()->tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1497,7 +1497,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2) { ORDER *order_item= item->order[i]; Item *item= *order_item->item; - Field *field= item->tmp_table_field(); + Field *field= item->real_item()->tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1548,7 +1548,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), Item *show_item= group_concat_item->args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->real_item()->tmp_table_field(); char *sv= f->ptr; f->ptr= (char *)key + f->abs_offset; String *res= f->val_str(&tmp,&tmp2); @@ -1716,7 +1716,7 @@ bool Item_func_group_concat::add() Item *show_item= args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->real_item()->tmp_table_field(); if (!f->is_null()) { record_is_null= FALSE; diff --git a/sql/item_sum.h b/sql/item_sum.h index bd946609745..219ca98dc45 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -734,4 +734,5 @@ class Item_func_group_concat : public Item_sum } String* val_str(String* str); Item *copy_or_same(THD* thd); + void no_rows_in_result() {} }; -- cgit v1.2.1 From fb3ab3c855fa8f154d1f018bb6eea155614289c9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Aug 2003 03:23:18 +0400 Subject: Fixed problem with absence of gmtime_r under Windows. include/my_pthread.h: HAVE_GMTIME_R should not be defined under Windows (it is ok for HAVE_LOCALTIME_R since there additional implementation in my_windcond.c. --- include/my_pthread.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/my_pthread.h b/include/my_pthread.h index d8374cad314..f4976abee10 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -111,7 +111,6 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #endif #define pthread_self() win_pthread_self #define HAVE_LOCALTIME_R 1 -#define HAVE_GMTIME_R 1 #define _REENTRANT 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 -- cgit v1.2.1 From 06b4c4bc35f37f9eb7af90d9b0c7414235d612e9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Aug 2003 17:14:10 +0400 Subject: comment left after merge was moved to correct place sql/sql_class.h: comment moved to correct place --- sql/sql_class.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index e10795c4d9d..8463c0226f5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -385,6 +385,7 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; + /* Determines if which non-standard SQL behaviour should be enabled */ ulong sql_mode; ulong default_week_format; ulong max_seeks_for_key; @@ -459,7 +460,6 @@ public: const char *host_or_ip; ulong client_capabilities; /* What the client supports */ - /* Determines if which non-standard SQL behaviour should be enabled */ ulong max_client_packet_length; ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ -- cgit v1.2.1 From 4ca3bee9e56352638523f14fd0d208c7c60177bb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Aug 2003 16:24:03 +0300 Subject: tmp_table_field() renamed to get_tmp_table_field() to avoid redifinition of tmp_table_field(TABLE *t_arg) sql/item_timefunc.h: no need redefine tmp_table_field(), it will be inherited --- sql/item.h | 6 +++--- sql/item_sum.cc | 8 ++++---- sql/item_timefunc.h | 11 ----------- sql/sql_select.cc | 12 ++++++------ 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/sql/item.h b/sql/item.h index 07be964092a..c7eb7fc2c1b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -140,7 +140,7 @@ public: virtual double val()=0; virtual longlong val_int()=0; virtual String *val_str(String*)=0; - virtual Field *tmp_table_field() { return 0; } + virtual Field *get_tmp_table_field() { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } virtual double val_result() { return val(); } @@ -267,7 +267,7 @@ public: { return field->type(); } - Field *tmp_table_field() { return result_field; } + Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } bool get_date(TIME *ltime,bool fuzzydate); bool get_date_result(TIME *ltime,bool fuzzydate); @@ -546,7 +546,7 @@ public: Item(thd, item), result_field(item.result_field) {} ~Item_result_field() {} /* Required with gcc 2.95 */ - Field *tmp_table_field() { return result_field; } + Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } table_map used_tables() const { return 1; } virtual void fix_length_and_dec()=0; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index c429346a2e6..84cb7eade05 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1460,7 +1460,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1, for (uint i= 0; i < item->arg_count_field; i++) { Item *field_item= item->args[i]; - Field *field= field_item->tmp_table_field(); + Field *field= field_item->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1491,7 +1491,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2) { ORDER *order_item= item->order[i]; Item *item= *order_item->item; - Field *field= item->tmp_table_field(); + Field *field= item->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1542,7 +1542,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), Item *show_item= group_concat_item->args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->get_tmp_table_field(); char *sv= f->ptr; f->ptr= (char *)key + f->abs_offset; String *res= f->val_str(&tmp,&tmp2); @@ -1709,7 +1709,7 @@ bool Item_func_group_concat::add() Item *show_item= args[i]; if (!show_item->const_item()) { - Field *f= show_item->tmp_table_field(); + Field *f= show_item->get_tmp_table_field(); if (!f->is_null()) { record_is_null= FALSE; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index d84267a5066..6dcf7d00ce1 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -327,7 +327,6 @@ public: max_length=10*default_charset()->mbmaxlen; } int save_in_field(Field *to, bool no_conversions); - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, default_charset())); @@ -342,7 +341,6 @@ public: Item_date_func(Item *a) :Item_str_func(a) {} Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {} enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_datetime(maybe_null, name, t_arg, default_charset())); @@ -366,7 +364,6 @@ public: longlong val_int() { return value; } String *val_str(String *str); void fix_length_and_dec(); - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -533,7 +530,6 @@ public: } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -634,7 +630,6 @@ public: bool get_date(TIME *ltime, bool fuzzy_date); const char *func_name() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, default_charset())); @@ -650,7 +645,6 @@ public: bool get_time(TIME *ltime); const char *func_name() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); @@ -665,7 +659,6 @@ public: String *val_str(String *str); const char *func_name() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_datetime(maybe_null, name, t_arg, default_charset())); @@ -684,7 +677,6 @@ public: decimals=0; max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); @@ -711,7 +703,6 @@ public: Change this when we support microseconds in TIME/DATETIME */ - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { if (cached_field_type == MYSQL_TYPE_TIME) @@ -735,7 +726,6 @@ public: decimals=0; max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); @@ -755,7 +745,6 @@ public: decimals=0; max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } - Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index de6b2ce443f..e38cd146265 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4789,7 +4789,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, keyinfo->algorithm= HA_KEY_ALG_UNDEF; for (; group ; group=group->next,key_part_info++) { - Field *field=(*group->item)->tmp_table_field(); + Field *field=(*group->item)->get_tmp_table_field(); bool maybe_null=(*group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -6057,7 +6057,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), Item *item= *group->item; if (item->maybe_null) { - Field *field=item->tmp_table_field(); + Field *field=item->get_tmp_table_field(); field->ptr[-1]= (byte) (field->is_null() ? 1 : 0); } } @@ -6926,7 +6926,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List &fields, Item *having) Item *item; while ((item=it++)) { - if (item->tmp_table_field() && ! item->const_item()) + if (item->get_tmp_table_field() && ! item->const_item()) field_count++; } @@ -7162,7 +7162,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length) pos->field= ((Item_field*) (*order->item))->field; else if (order->item[0]->type() == Item::SUM_FUNC_ITEM && !order->item[0]->const_item()) - pos->field= ((Item_sum*) order->item[0])->tmp_table_field(); + pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field(); else if (order->item[0]->type() == Item::COPY_STR_ITEM) { // Blob patch pos->item= ((Item_copy_string*) (*order->item))->item; @@ -7759,7 +7759,7 @@ calc_group_buffer(JOIN *join,ORDER *group) join->group= 1; for (; group ; group=group->next) { - Field *field=(*group->item)->tmp_table_field(); + Field *field=(*group->item)->get_tmp_table_field(); if (field) { if (field->type() == FIELD_TYPE_BLOB) @@ -8103,7 +8103,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, { item_field= item->get_tmp_table_item(thd); } - else if ((field= item->tmp_table_field())) + else if ((field= item->get_tmp_table_field())) { if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) item_field= ((Item_sum*) item)->result_item(field); -- cgit v1.2.1 From e9183c74f2cbd5351adaf5f734b26b490a163d90 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Aug 2003 22:13:57 -0400 Subject: Fix VC++ compiler error with redifinition return type include/thr_alarm.h: Fix VC++ compiler error with redefinition return type --- include/thr_alarm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 439f046252f..8ff4472f700 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -100,7 +100,7 @@ typedef struct st_alarm { #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A)!= 0) void init_thr_alarm(uint max_alarm); -bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); +my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); void end_thr_alarm(my_bool free_structures); -- cgit v1.2.1 From 8309920506e57b94a8a56693b248be284f3d3c44 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Aug 2003 17:13:10 +0300 Subject: Fix for a compilation problem with VC++ --- sql/sql_union.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 24497589c73..011c1a5a8b8 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -116,7 +116,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, bool tables_and_fields_initied) { SELECT_LEX *lex_select_save= thd->lex.current_select; - SELECT_LEX *select_cursor; + SELECT_LEX *select_cursor,*sl; DBUG_ENTER("st_select_lex_unit::prepare"); if (prepared) @@ -130,7 +130,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, t_and_f= tables_and_fields_initied; bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM)); - thd->lex.current_select= select_cursor= first_select_in_union(); + thd->lex.current_select= sl= select_cursor= first_select_in_union(); /* Global option */ if (t_and_f) { @@ -185,7 +185,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, union_result->not_describe=1; union_result->tmp_table_param=tmp_table_param; - for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) + for (;sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK, -- cgit v1.2.1 From 674f3881dff0baa13a0b19b7a577bf96a80ce2d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Aug 2003 18:21:24 +0300 Subject: Two small fixes mysql-test/r/isam.result: Fixing results to match test changes sql/sql_union.cc: Better fix for VC++ --- mysql-test/r/isam.result | 8 -------- sql/sql_union.cc | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/isam.result b/mysql-test/r/isam.result index b83185b0c01..bacb88a27fc 100644 --- a/mysql-test/r/isam.result +++ b/mysql-test/r/isam.result @@ -1,13 +1,5 @@ drop table if exists t1,t2; create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a)) type=isam; -Warnings: -Warning 1263 Data truncated for column 'b' at row 1 -Warnings: -Warning 1263 Data truncated for column 'b' at row 1 -Warnings: -Warning 1263 Data truncated for column 'b' at row 1 -Warnings: -Warning 1263 Data truncated for column 'b' at row 1 delete from t1 where (a & 1); select sum(length(b)) from t1; sum(length(b)) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 011c1a5a8b8..55f697e9981 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -326,8 +326,8 @@ int st_select_lex_unit::exec() We get this from the difference of between total number of possible rows and actual rows added to the temporary table. */ - add_rows+= (ulonglong) (thd->limit_found_rows - (table->file->records - - records_at_start)); + add_rows+= (ha_rows) (thd->limit_found_rows - (ulonglong) + ((table->file->records - records_at_start))); } } } -- cgit v1.2.1 From 8a548ffd9c46f111d480b51a1e30dad44433ba80 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Sep 2003 15:16:20 +0400 Subject: Implemented replication over SSL Added proper options to CHANGE MASTER TO, new fields to SHOW SLAVE STATUS, Honoring this parameters during connection to master. Introduced new format of master.info file include/mysqld_error.h: Added error code for "slave without SSL ignored SSL params warning" mysql-test/Makefile.am: Copy files required for rpl_openssl test during the make process mysql-test/r/rpl000015.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_empty_master_crash.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_flush_log_loop.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_log.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_log_pos.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_redirect.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_replicate_do.result: Added fields to SHOW SLAVE STATUS for replication over SSL mysql-test/r/rpl_rotate_logs.result: Added fields to SHOW SLAVE STATUS for replication over SSL sql/lex.h: Added MASTER_SSL lexems for CHANGE MASTER sql/mysqld.cc: Added --master-ssl-ca parameter. Fixed description of other master-ssl parameters sql/repl_failsafe.cc: Added SSL support to connect_to_master() sql/share/czech/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/danish/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/dutch/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/english/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/estonian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/french/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/german/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/greek/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/hungarian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/italian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/japanese/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/korean/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/norwegian-ny/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/norwegian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/polish/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/portuguese/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/romanian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/russian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/serbian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/slovak/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/spanish/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/swedish/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/share/ukrainian/errmsg.txt: Added "slave without SSL ignored SSL params" warning sql/slave.cc: Introduced new format of master.info file Added support of SSL params in master.info and SHOW SLAVE STATUS Added support of SSL connections sql/slave.h: Added SSL parameters to MASTER_INFO sql/sql_lex.h: Added SSL parameters for CHANGE MASTER TO sql/sql_repl.cc: Added SSL parameters for CHANGE MASTER TO sql/sql_yacc.yy: Added SSL parameters for CHANGE MASTER TO --- include/mysqld_error.h | 3 +- mysql-test/Makefile.am | 12 ++- mysql-test/r/rpl000015.result | 14 +-- mysql-test/r/rpl_empty_master_crash.result | 2 +- mysql-test/r/rpl_flush_log_loop.result | 4 +- mysql-test/r/rpl_log.result | 4 +- mysql-test/r/rpl_log_pos.result | 16 ++-- mysql-test/r/rpl_openssl.result | 30 ++++++ mysql-test/r/rpl_redirect.result | 2 +- mysql-test/r/rpl_replicate_do.result | 4 +- mysql-test/r/rpl_rotate_logs.result | 12 +-- mysql-test/t/rpl_openssl.test | 60 ++++++++++++ sql/lex.h | 6 ++ sql/mysqld.cc | 32 ++++--- sql/repl_failsafe.cc | 11 +++ sql/share/czech/errmsg.txt | 1 + sql/share/danish/errmsg.txt | 1 + sql/share/dutch/errmsg.txt | 1 + sql/share/english/errmsg.txt | 1 + sql/share/estonian/errmsg.txt | 1 + sql/share/french/errmsg.txt | 1 + sql/share/german/errmsg.txt | 1 + sql/share/greek/errmsg.txt | 1 + sql/share/hungarian/errmsg.txt | 1 + sql/share/italian/errmsg.txt | 1 + sql/share/japanese/errmsg.txt | 1 + sql/share/korean/errmsg.txt | 1 + sql/share/norwegian-ny/errmsg.txt | 1 + sql/share/norwegian/errmsg.txt | 1 + sql/share/polish/errmsg.txt | 1 + sql/share/portuguese/errmsg.txt | 1 + sql/share/romanian/errmsg.txt | 1 + sql/share/russian/errmsg.txt | 1 + sql/share/serbian/errmsg.txt | 1 + sql/share/slovak/errmsg.txt | 1 + sql/share/spanish/errmsg.txt | 1 + sql/share/swedish/errmsg.txt | 1 + sql/share/ukrainian/errmsg.txt | 1 + sql/slave.cc | 148 ++++++++++++++++++++++++++--- sql/slave.h | 12 ++- sql/sql_lex.h | 7 ++ sql/sql_repl.cc | 19 ++++ sql/sql_yacc.yy | 37 ++++++++ 43 files changed, 398 insertions(+), 60 deletions(-) create mode 100644 mysql-test/r/rpl_openssl.result create mode 100644 mysql-test/t/rpl_openssl.test diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 17ededfbb52..e5c2898d0e7 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -288,4 +288,5 @@ #define ER_CANT_AGGREGATE_NCOLLATIONS 1269 #define ER_VARIABLE_IS_NOT_STRUCT 1270 #define ER_UNKNOWN_COLLATION 1271 -#define ER_ERROR_MESSAGES 272 +#define ER_SLAVE_IGNORED_SSL_PARAMS 1272 +#define ER_ERROR_MESSAGES 273 diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index fb97dd5b1de..2babb6fba66 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -21,8 +21,9 @@ benchdir_root= $(prefix) testdir = $(benchdir_root)/mysql-test EXTRA_SCRIPTS = mysql-test-run.sh install_test_db.sh EXTRA_DIST = $(EXTRA_SCRIPTS) -test_SCRIPTS = mysql-test-run install_test_db -CLEANFILES = $(test_SCRIPTS) +test_SCRIPTS = mysql-test-run install_test_db +test_DATA = std_data/client-key.pem std_data/client-cert.pem std_data/cacert.pem +CLEANFILES = $(test_SCRIPTS) $(test_DATA) dist-hook: mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \ @@ -32,6 +33,8 @@ dist-hook: $(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(distdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(distdir)/std_data + install-data-local: $(mkinstalldirs) \ @@ -49,6 +52,11 @@ install-data-local: $(INSTALL_DATA) $(srcdir)/include/*.inc $(DESTDIR)$(testdir)/include $(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data $(INSTALL_DATA) $(srcdir)/std_data/des_key_file $(DESTDIR)$(testdir)/std_data + $(INSTALL_DATA) $(srcdir)/std_data/*.pem $(DESTDIR)$(testdir)/std_data + +std_data/%.pem: + @CP@ $(top_srcdir)/SSL/$(@F) $(srcdir)/std_data + SUFFIXES = .sh diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result index 047f1ac5044..8a9f8320218 100644 --- a/mysql-test/r/rpl000015.result +++ b/mysql-test/r/rpl000015.result @@ -4,20 +4,20 @@ File Position Binlog_do_db Binlog_ignore_db master-bin.000001 79 reset slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key change master to master_host='127.0.0.1'; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 No change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 No start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 7 master-bin.000001 79 slave-relay-bin.000001 123 master-bin.000001 Yes Yes 0 0 79 123 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 7 master-bin.000001 79 slave-relay-bin.000001 123 master-bin.000001 Yes Yes 0 0 79 123 No drop table if exists t1; create table t1 (n int); insert into t1 values (10),(45),(90); diff --git a/mysql-test/r/rpl_empty_master_crash.result b/mysql-test/r/rpl_empty_master_crash.result index 6aac1cbfc91..10b1fdeb0ec 100644 --- a/mysql-test/r/rpl_empty_master_crash.result +++ b/mysql-test/r/rpl_empty_master_crash.result @@ -5,7 +5,7 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key load table t1 from master; ERROR 08S01: Error connecting to master: Master is not configured load table t1 from master; diff --git a/mysql-test/r/rpl_flush_log_loop.result b/mysql-test/r/rpl_flush_log_loop.result index 954ab107123..b9cfa7fb55d 100644 --- a/mysql-test/r/rpl_flush_log_loop.result +++ b/mysql-test/r/rpl_flush_log_loop.result @@ -13,5 +13,5 @@ master_password='',master_port=SLAVE_PORT; start slave; flush logs; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 79 relay-log.000001 122 slave-bin.000001 Yes Yes 0 0 79 122 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root SLAVE_PORT 60 slave-bin.000001 79 relay-log.000001 122 slave-bin.000001 Yes Yes 0 0 79 122 No diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 050e9274a99..db8c383b0a0 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -92,7 +92,7 @@ slave-bin.000002 4 Query 1 110 use `test`; create table t1 (n int) slave-bin.000002 62 Query 1 168 use `test`; insert into t1 values (1) slave-bin.000002 122 Query 1 228 use `test`; drop table t1 show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 slave-relay-bin.000002 1531 master-bin.000002 Yes Yes 0 0 276 1535 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 slave-relay-bin.000002 1531 master-bin.000002 Yes Yes 0 0 276 1535 No show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/r/rpl_log_pos.result b/mysql-test/r/rpl_log_pos.result index b42e7ff5dc4..7787243410d 100644 --- a/mysql-test/r/rpl_log_pos.result +++ b/mysql-test/r/rpl_log_pos.result @@ -8,26 +8,26 @@ show master status; File Position Binlog_do_db Binlog_ignore_db master-bin.000001 79 show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 127 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 127 No stop slave; change master to master_log_pos=73; start slave; stop slave; change master to master_log_pos=73; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 73 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 73 4 No start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 slave-relay-bin.000001 4 master-bin.000001 No Yes 0 0 73 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 73 slave-relay-bin.000001 4 master-bin.000001 No Yes 0 0 73 4 No stop slave; change master to master_log_pos=173; start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 173 slave-relay-bin.000001 4 master-bin.000001 No Yes 0 0 173 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 173 slave-relay-bin.000001 4 master-bin.000001 No Yes 0 0 173 4 No show master status; File Position Binlog_do_db Binlog_ignore_db master-bin.000001 79 diff --git a/mysql-test/r/rpl_openssl.result b/mysql-test/r/rpl_openssl.result new file mode 100644 index 00000000000..43cf6bf8176 --- /dev/null +++ b/mysql-test/r/rpl_openssl.result @@ -0,0 +1,30 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +grant replication slave on *.* to replssl@'%' require ssl; +create table t1 (t int); +stop slave; +change master to master_user='replssl',master_password=''; +start slave; +insert into t1 values (1); +select * from t1; +t +stop slave; +change master to master_ssl=1 , master_ssl_ca ='MYSQL_TEST_DIR/std_data/cacert.pem', master_ssl_cert='MYSQL_TEST_DIR/std_data/client-cert.pem', master_ssl_key='MYSQL_TEST_DIR/std_data/client-key.pem'; +start slave; +select * from t1; +t +1 +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 289 slave-relay-bin.000001 64 master-bin.000001 Yes Yes 0 0 289 64 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem +stop slave; +change master to master_user='root',master_password='', master_ssl=0; +start slave; +drop table t1; +show slave status; +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 337 slave-relay-bin.000001 52 master-bin.000001 Yes Yes 0 0 337 52 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem diff --git a/mysql-test/r/rpl_redirect.result b/mysql-test/r/rpl_redirect.result index 79ff6685706..ce82ef54355 100644 --- a/mysql-test/r/rpl_redirect.result +++ b/mysql-test/r/rpl_redirect.result @@ -5,7 +5,7 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; SHOW SLAVE STATUS; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key SHOW SLAVE HOSTS; Server_id Host Port Rpl_recovery_rank Master_id 2 127.0.0.1 SLAVE_PORT 2 1 diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index 4d740cafbd0..2daa9cd0ef3 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -27,5 +27,5 @@ select * from t11; ERROR 42S02: Table 'test.t11' doesn't exist drop table if exists t1,t2,t11; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 1281 slave-relay-bin.000002 1325 master-bin.000001 Yes Yes test.t1 0 0 1281 1329 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 1281 slave-relay-bin.000002 1325 master-bin.000001 Yes Yes test.t1 0 0 1281 1329 No diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 753edebea60..9261ade5225 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -15,8 +15,8 @@ insert into temp_table values ("testing temporary tables"); create table t1 (s text); insert into t1 values('Could not break slave'),('Tried hard'); show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.000001 417 slave-relay-bin.000001 461 master-bin.000001 Yes Yes 0 0 417 461 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 60 master-bin.000001 417 slave-relay-bin.000001 461 master-bin.000001 Yes Yes 0 0 417 461 No select * from t1; s Could not break slave @@ -56,8 +56,8 @@ Log_name master-bin.000003 insert into t2 values (65); show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.000003 290 slave-relay-bin.000001 1088 master-bin.000003 Yes Yes 0 0 290 1088 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 60 master-bin.000003 290 slave-relay-bin.000001 1088 master-bin.000003 Yes Yes 0 0 290 1088 No select * from t2; m 34 @@ -82,8 +82,8 @@ select * from t4; a testing temporary tables part 2 show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 60 master-bin.000006 838 slave-relay-bin.000001 8067 master-bin.000006 Yes Yes 0 0 838 8067 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 60 master-bin.000006 838 slave-relay-bin.000001 8067 master-bin.000006 Yes Yes 0 0 838 8067 No lock tables t3 read; select count(*) from t3 where n >= 4; count(*) diff --git a/mysql-test/t/rpl_openssl.test b/mysql-test/t/rpl_openssl.test new file mode 100644 index 00000000000..bd658786bd7 --- /dev/null +++ b/mysql-test/t/rpl_openssl.test @@ -0,0 +1,60 @@ +source include/have_openssl_1.inc; +source include/master-slave.inc; + +# We don't test all types of ssl auth params here since it's a bit hard +# until problems with OpenSSL 0.9.7 are unresolved + +# creating replication user for whom ssl auth is required +# preparing playground +connection master; +grant replication slave on *.* to replssl@'%' require ssl; +create table t1 (t int); +save_master_pos; + +#syncing with master +connection slave; +sync_with_master; + +#trying to use this user without ssl +stop slave; +change master to master_user='replssl',master_password=''; +start slave; + +#showing that replication don't work +connection master; +insert into t1 values (1); +#reasonable timeout for changes to propagate to slave +sleep 3; +connection slave; +select * from t1; + +#showing that replication could work with ssl params +stop slave; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +eval change master to master_ssl=1 , master_ssl_ca ='$MYSQL_TEST_DIR/std_data/cacert.pem', master_ssl_cert='$MYSQL_TEST_DIR/std_data/client-cert.pem', master_ssl_key='$MYSQL_TEST_DIR/std_data/client-key.pem'; +start slave; + +#avoiding unneeded sleeps +connection master; +save_master_pos; +connection slave; +sync_with_master; + +#checking that replication is ok +select * from t1; + +#checking show slave status +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_MYPORT +show slave status; + +#checking if replication works without ssl also performing clean up +stop slave; +change master to master_user='root',master_password='', master_ssl=0; +start slave; +connection master; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR $MASTER_MYPORT MASTER_MYPORT +show slave status; diff --git a/sql/lex.h b/sql/lex.h index c2860f4551a..61b7162b8fe 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -249,6 +249,12 @@ static SYMBOL symbols[] = { { "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0}, { "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0}, { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0}, + { "MASTER_SSL", SYM(MASTER_SSL_SYM),0,0}, + { "MASTER_SSL_CA", SYM(MASTER_SSL_CA_SYM),0,0}, + { "MASTER_SSL_CAPATH",SYM(MASTER_SSL_CAPATH_SYM),0,0}, + { "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM),0,0}, + { "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM),0,0}, + { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM),0,0}, { "MASTER_USER", SYM(MASTER_USER_SYM),0,0}, { "MAX_ROWS", SYM(MAX_ROWS),0,0}, { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR), 0,0}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8ddcbdc572f..7f839c9f0e8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -359,15 +359,15 @@ pthread_t signal_thread; pthread_attr_t connection_attrib; /* replication parameters, if master_host is not NULL, we are a slave */ -my_bool master_ssl; uint master_port= MYSQL_PORT, master_connect_retry = 60; uint report_port= MYSQL_PORT; ulong master_retry_count=0; char *master_user, *master_password, *master_host, *master_info_file; -char *relay_log_info_file, *master_ssl_key, *master_ssl_cert; -char *master_ssl_capath, *master_ssl_cipher, *report_user; -char *report_password, *report_host; +char *relay_log_info_file, *report_user, *report_password, *report_host; char *opt_relay_logname = 0, *opt_relaylog_index_name=0; +my_bool master_ssl; +char *master_ssl_key, *master_ssl_cert; +char *master_ssl_ca, *master_ssl_capath, *master_ssl_cipher; /* Static variables */ @@ -3389,7 +3389,7 @@ enum options OPT_MASTER_RETRY_COUNT, OPT_MASTER_SSL, OPT_MASTER_SSL_KEY, OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH, - OPT_MASTER_SSL_CIPHER, + OPT_MASTER_SSL_CIPHER, OPT_MASTER_SSL_CA, OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB, OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES, OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB, @@ -3723,27 +3723,28 @@ thread is in the master's binlogs.", (gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl", OPT_MASTER_SSL, - "Planned to enable the slave to connect to the master using SSL. Does nothing yet.", + "Enable the slave to connect to the master using SSL.", (gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-key", OPT_MASTER_SSL_KEY, - "Master SSL keyfile name. Only applies if you have enabled master-ssl. Does \ -nothing yet.", + "Master SSL keyfile name. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, "Master SSL certificate file name. Only applies if you have enabled \ -master-ssl. Does nothing yet.", +master-ssl", (gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"master-ssl-ca", OPT_MASTER_SSL_CA, + "Master SSL CA file. Only applies if you have enabled master-ssl.", + (gptr*) &master_ssl_ca, (gptr*) &master_ssl_ca, 0, GET_STR, OPT_ARG, + 0, 0, 0, 0, 0, 0}, {"master-ssl-capath", OPT_MASTER_SSL_CAPATH, - "Master SSL CA path. Only applies if you have enabled master-ssl. \ -Does nothing yet.", + "Master SSL CA path. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, - "Master SSL cipher. Only applies if you have enabled master-ssl. \ -Does nothing yet.", + "Master SSL cipher. Only applies if you have enabled master-ssl.", (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"myisam-recover", OPT_MYISAM_RECOVER, @@ -4717,8 +4718,9 @@ static void mysql_init_variables(void) master_user= (char*) "test"; master_password= master_host= 0; master_info_file= (char*) "master.info", - relay_log_info_file= (char*) "relay-log.info", - master_ssl_key= master_ssl_cert= master_ssl_capath= master_ssl_cipher= 0; + relay_log_info_file= (char*) "relay-log.info"; + master_ssl_key= master_ssl_cert= master_ssl_ca= + master_ssl_capath= master_ssl_cipher= 0; report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 60af9a92c76..47459896cd7 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -669,6 +669,17 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) } mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); + +#ifdef HAVE_OPENSSL + if (mi->ssl) + mysql_ssl_set(mysql, + mi->ssl_key[0]?mi->ssl_key:0, + mi->ssl_cert[0]?mi->ssl_cert:0, + mi->ssl_ca[0]?mi->ssl_ca:0, + mi->ssl_capath[0]?mi->ssl_capath:0, + mi->ssl_cipher[0]?mi->ssl_cipher:0); +#endif + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index b43c4b43b50..44482efaa86 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -277,3 +277,4 @@ v/* "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 2eb9e6d2219..2fe03e6d3cc 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -271,3 +271,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 2a663a176f8..36400c7890f 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -279,3 +279,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index f4019d63055..9e824ae5663 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -273,3 +273,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index d3a38ede5bc..bc7f54a2edc 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -273,3 +273,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index ccff24c5759..e33fe901714 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 52f3eb78c11..0613a726bde 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -277,3 +277,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 1ce052bdf22..1168e233e03 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 6143ea2a1c4..274a81ae1a3 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -270,3 +270,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8164757d823..c5fc0315cf1 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 747d3611cc9..b77f749409f 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -270,3 +270,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 93d86d32937..4e50bfe1bc5 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index e9319246fc6..663ef2110ea 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -270,3 +270,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index edb5854db7e..358bbc4e1fa 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -270,3 +270,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 27b4d0d661f..600424bc27b 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -272,3 +272,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 60ace09ab33..ceb024ba576 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8824d64876a..d4782649333 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -272,3 +272,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index ddfc0a8f7de..625fee9c3bc 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -270,3 +270,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 9e2a37e4053..e6609d391dd 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -264,3 +264,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index ed1d8cadb80..82672a7570f 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -276,3 +276,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 5f3a2f38109..94a1b618688 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -269,3 +269,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index d108618834e..b797f343e14 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -268,3 +268,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 96b9f40feac..152422b9fae 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -273,3 +273,4 @@ "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." diff --git a/sql/slave.cc b/sql/slave.cc index 37979576b73..210d2c0c744 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1409,6 +1409,7 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) DBUG_RETURN(0); } +#define LINES_IN_MASTER_INFO_WITH_SSL 14 int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, @@ -1462,6 +1463,18 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); mi->port = master_port; mi->connect_retry = master_connect_retry; + + mi->ssl= master_ssl; + if (master_ssl_ca) + strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1); + if (master_ssl_capath) + strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1); + if (master_ssl_cert) + strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1); + if (master_ssl_cipher) + strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1); + if (master_ssl_key) + strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1); } else // file exists { @@ -1473,12 +1486,50 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, goto err; mi->fd = fd; - int port, connect_retry, master_log_pos; - + int port, connect_retry, master_log_pos, ssl= 0, lines; + char *first_non_digit; + + /* + Starting from 4.1.x master.info has new format. Now its + first line contains number of lines in file. By reading this + number we will be always distinguish to which version our + master.info corresponds to. We can't simply count lines in + file since versions before 4.1.x could generate files with more + lines than needed. + If first line doesn't contain a number or contain number less than + 14 then such file is treated like file from pre 4.1.1 version. + There is no ambiguity when reading an old master.info, as before + 4.1.1, the first line contained the binlog's name, which is either + empty or has an extension (contains a '.'), so can't be confused + with an integer. + + So we're just reading first line and trying to figure which version + is this. + */ + + /* + The first row is temporarily stored in mi->master_log_name, + if it is line count and not binlog name (new format) it will be + overwritten by the second row later. + */ if (init_strvar_from_file(mi->master_log_name, sizeof(mi->master_log_name), &mi->file, - "") || - init_intvar_from_file(&master_log_pos, &mi->file, 4) || + "")) + goto errwithmsg; + + lines= strtoul(mi->master_log_name, &first_non_digit, 10); + + if (mi->master_log_name[0]!='\0' && + *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL) + { // Seems to be new format + if (init_strvar_from_file(mi->master_log_name, + sizeof(mi->master_log_name), &mi->file, "")) + goto errwithmsg; + } + else + lines= 7; + + if (init_intvar_from_file(&master_log_pos, &mi->file, 4) || init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, master_host) || init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, @@ -1488,10 +1539,34 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, init_intvar_from_file(&port, &mi->file, master_port) || init_intvar_from_file(&connect_retry, &mi->file, master_connect_retry)) - { - sql_print_error("Error reading master configuration"); - goto err; - } + goto errwithmsg; + + /* + If file has ssl part use it even if we have server without + SSL support. But these option will be ignored later when + slave will try connect to master, so in this case warning + is printed. + */ + if (lines >= LINES_IN_MASTER_INFO_WITH_SSL && + (init_intvar_from_file(&ssl, &mi->file, master_ssl) || + init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca), + &mi->file, master_ssl_ca) || + init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath), + &mi->file, master_ssl_capath) || + init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert), + &mi->file, master_ssl_cert) || + init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher), + &mi->file, master_ssl_cipher) || + init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key), + &mi->file, master_ssl_key))) + goto errwithmsg; +#ifndef HAVE_OPENSSL + if (ssl) + sql_print_error("SSL information in the master info file " + "('%s') are ignored because this MySQL slave was compiled " + "without SSL support.", fname); +#endif /* HAVE_OPENSSL */ + /* This has to be handled here as init_intvar_from_file can't handle my_off_t types @@ -1499,6 +1574,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, mi->master_log_pos= (my_off_t) master_log_pos; mi->port= (uint) port; mi->connect_retry= (uint) connect_retry; + mi->ssl= (my_bool) ssl; } DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, @@ -1514,7 +1590,10 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, error=test(flush_master_info(mi)); pthread_mutex_unlock(&mi->data_lock); DBUG_RETURN(error); - + +errwithmsg: + sql_print_error("Error reading master configuration"); + err: if (fd >= 0) { @@ -1648,6 +1727,18 @@ int show_master_info(THD* thd, MASTER_INFO* mi) MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_return_int("Relay_log_space", 10, MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_empty_string("Master_SSL_Allowed", 7)); + field_list.push_back(new Item_empty_string("Master_SSL_CA_File", + sizeof(mi->ssl_ca))); + field_list.push_back(new Item_empty_string("Master_SSL_CA_Path", + sizeof(mi->ssl_capath))); + field_list.push_back(new Item_empty_string("Master_SSL_Cert", + sizeof(mi->ssl_cert))); + field_list.push_back(new Item_empty_string("Master_SSL_Cipher", + sizeof(mi->ssl_cipher))); + field_list.push_back(new Item_empty_string("Master_SSL_Key", + sizeof(mi->ssl_key))); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); @@ -1694,6 +1785,17 @@ int show_master_info(THD* thd, MASTER_INFO* mi) protocol->store((uint32) mi->rli.slave_skip_counter); protocol->store((ulonglong) mi->rli.group_master_log_pos); protocol->store((ulonglong) mi->rli.log_space_total); +#ifdef HAVE_OPENSSL + protocol->store(mi->ssl? "Yes":"No", &my_charset_bin); +#else + protocol->store(mi->ssl? "Ignored":"No", &my_charset_bin); +#endif + protocol->store(mi->ssl_ca, &my_charset_bin); + protocol->store(mi->ssl_capath, &my_charset_bin); + protocol->store(mi->ssl_cert, &my_charset_bin); + protocol->store(mi->ssl_cipher, &my_charset_bin); + protocol->store(mi->ssl_key, &my_charset_bin); + pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1712,11 +1814,22 @@ bool flush_master_info(MASTER_INFO* mi) DBUG_ENTER("flush_master_info"); DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos)); + /* + In certain cases this code may create master.info files that seems + corrupted, because of extra lines filled with garbage in the end + file (this happens if new contents take less space than previous + contents of file). But because of number of lines in the first line + of file we don't care about this garbage. + */ + my_b_seek(file, 0L); - my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", - mi->master_log_name, llstr(mi->master_log_pos, lbuf), + my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n", + LINES_IN_MASTER_INFO_WITH_SSL, + mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, - mi->password, mi->port, mi->connect_retry); + mi->password, mi->port, mi->connect_retry, + (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, + mi->ssl_cipher, mi->ssl_key); flush_io_cache(file); DBUG_RETURN(0); } @@ -3061,6 +3174,17 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout); + +#ifdef HAVE_OPENSSL + if (mi->ssl) + mysql_ssl_set(mysql, + mi->ssl_key[0]?mi->ssl_key:0, + mi->ssl_cert[0]?mi->ssl_cert:0, + mi->ssl_ca[0]?mi->ssl_ca:0, + mi->ssl_capath[0]?mi->ssl_capath:0, + mi->ssl_cipher[0]?mi->ssl_cipher:0); +#endif + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname); /* This one is not strictly needed but we have it here for completeness */ mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir); diff --git a/sql/slave.h b/sql/slave.h index 668fff52d08..9d21ca5925b 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -293,6 +293,9 @@ typedef struct st_master_info char host[HOSTNAME_LENGTH+1]; char user[USERNAME_LENGTH+1]; char password[HASH_PASSWORD_LENGTH+1]; + my_bool ssl; // enables use of SSL connection if true + char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; + char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; pthread_mutex_t data_lock,run_lock; pthread_cond_t data_cond,start_cond,stop_cond; THD *io_thd; @@ -310,10 +313,13 @@ typedef struct st_master_info volatile ulong slave_run_id; st_master_info() - :fd(-1), io_thd(0), inited(0), old_format(0),abort_slave(0), + :fd(-1), ssl(0), io_thd(0), inited(0), old_format(0),abort_slave(0), slave_running(0), slave_run_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; + ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; + ssl_cipher[0]= 0; ssl_key[0]= 0; + bzero(&file, sizeof(file)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); @@ -459,6 +465,10 @@ extern my_string master_user, master_password, master_host, master_info_file, relay_log_info_file, report_user, report_host, report_password; +extern my_bool master_ssl; +extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert, + master_ssl_cipher, master_ssl_key; + extern I_List replicate_do_db, replicate_ignore_db; extern I_List replicate_rewrite_db; extern I_List threads; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index faf7e16e54a..ed9132d5d20 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -85,6 +85,13 @@ typedef struct st_lex_master_info uint port, connect_retry; ulonglong pos; ulong server_id; + /* + Variable for MASTER_SSL option. + MASTER_SSL=0 in CHANGE MASTER TO corresponds to SSL_DISABLE + MASTER_SSL=1 corresponds to SSL_ENABLE + */ + enum {SSL_UNCHANGED=0, SSL_DISABLE, SSL_ENABLE} ssl; + char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher; char *relay_log_name; ulong relay_log_pos; } LEX_MASTER_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 121411379f8..f6e5ad127df 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -888,6 +888,25 @@ int change_master(THD* thd, MASTER_INFO* mi) mi->port = lex_mi->port; if (lex_mi->connect_retry) mi->connect_retry = lex_mi->connect_retry; + + if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED) + mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE); + if (lex_mi->ssl_ca) + strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1); + if (lex_mi->ssl_capath) + strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1); + if (lex_mi->ssl_cert) + strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1); + if (lex_mi->ssl_cipher) + strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1); + if (lex_mi->ssl_key) + strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1); +#ifndef HAVE_OPENSSL + if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath || + lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS)); +#endif if (lex_mi->relay_log_name) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 90c586dc2f1..175919d1cd4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -276,6 +276,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token MASTER_PORT_SYM %token MASTER_CONNECT_RETRY_SYM %token MASTER_SERVER_ID_SYM +%token MASTER_SSL_SYM +%token MASTER_SSL_CA_SYM +%token MASTER_SSL_CAPATH_SYM +%token MASTER_SSL_CERT_SYM +%token MASTER_SSL_CIPHER_SYM +%token MASTER_SSL_KEY_SYM %token RELAY_LOG_FILE_SYM %token RELAY_LOG_POS_SYM %token MATCH @@ -844,6 +850,31 @@ master_def: /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */ Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos); } + | MASTER_SSL_SYM EQ ULONG_NUM + { + Lex->mi.ssl= $3 ? + LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE; + } + | MASTER_SSL_CA_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_ca= $3.str; + } + | MASTER_SSL_CAPATH_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_capath= $3.str; + } + | MASTER_SSL_CERT_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_cert= $3.str; + } + | MASTER_SSL_CIPHER_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_cipher= $3.str; + } + | MASTER_SSL_KEY_SYM EQ TEXT_STRING_sys + { + Lex->mi.ssl_key= $3.str; + } ; @@ -4430,6 +4461,12 @@ keyword: | MASTER_USER_SYM {} | MASTER_PASSWORD_SYM {} | MASTER_CONNECT_RETRY_SYM {} + | MASTER_SSL_SYM {} + | MASTER_SSL_CA_SYM {} + | MASTER_SSL_CAPATH_SYM {} + | MASTER_SSL_CERT_SYM {} + | MASTER_SSL_CIPHER_SYM {} + | MASTER_SSL_KEY_SYM {} | MAX_CONNECTIONS_PER_HOUR {} | MAX_QUERIES_PER_HOUR {} | MAX_UPDATES_PER_HOUR {} -- cgit v1.2.1 From 651898adfce345138363961769c6fdfd6da95532 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Sep 2003 19:13:19 +0400 Subject: Updated various tests results which were missed during auto-merge with replication over SSL patch. mysql-test/r/rpl_error_ignored_table.result: New SSL related fields in SHOW SLAVE STATUS mysql-test/r/rpl_loaddata.result: New SSL related fields in SHOW SLAVE STATUS mysql-test/r/rpl_max_relay_size.result: New SSL related fields in SHOW SLAVE STATUS mysql-test/r/rpl_openssl.result: Post merge update of SHOW SLAVE STATUS result mysql-test/r/rpl_reset_slave.result: New SSL related fields in SHOW SLAVE STATUS mysql-test/r/rpl_rotate_logs.result: Fixed bad manual merge result --- mysql-test/r/rpl_error_ignored_table.result | 4 ++-- mysql-test/r/rpl_loaddata.result | 12 ++++++------ mysql-test/r/rpl_max_relay_size.result | 24 ++++++++++++------------ mysql-test/r/rpl_openssl.result | 4 ++-- mysql-test/r/rpl_reset_slave.result | 16 ++++++++-------- mysql-test/r/rpl_rotate_logs.result | 2 +- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result index f22b62838bb..23b92e270a6 100644 --- a/mysql-test/r/rpl_error_ignored_table.result +++ b/mysql-test/r/rpl_error_ignored_table.result @@ -8,8 +8,8 @@ create table t1 (a int primary key); insert into t1 values (1),(1); ERROR 23000: Duplicate entry '1' for key 1 show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 213 slave-relay-bin.000002 257 master-bin.000001 Yes Yes test.t1 0 0 213 257 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 213 slave-relay-bin.000002 257 master-bin.000001 Yes Yes test.t1 0 0 213 257 No show tables like 't1'; Tables_in_test (t1) drop table t1; diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index 55dcf2f4f0f..8b31d41412d 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -28,8 +28,8 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t1; set global sql_slave_skip_counter=1; start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 1311 slave-relay-bin.000002 1355 master-bin.000001 Yes Yes 0 0 1311 1355 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 1311 slave-relay-bin.000002 1355 master-bin.000001 Yes Yes 0 0 1311 1355 No set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -38,8 +38,8 @@ stop slave; change master to master_user='test'; change master to master_user='root'; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 1442 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 1442 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 1442 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 1442 4 No set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -49,5 +49,5 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t1; stop slave; reset slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 No diff --git a/mysql-test/r/rpl_max_relay_size.result b/mysql-test/r/rpl_max_relay_size.result index 741b3538799..98efa3d848e 100644 --- a/mysql-test/r/rpl_max_relay_size.result +++ b/mysql-test/r/rpl_max_relay_size.result @@ -15,8 +15,8 @@ select @@global.max_relay_log_size; 4096 start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000014 1221 master-bin.000001 Yes Yes 0 0 50477 1221 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000014 1221 master-bin.000001 Yes Yes 0 0 50477 1221 No stop slave; reset slave; set global max_relay_log_size=(5*4096); @@ -25,8 +25,8 @@ select @@global.max_relay_log_size; 20480 start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000004 9457 master-bin.000001 Yes Yes 0 0 50477 9457 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000004 9457 master-bin.000001 Yes Yes 0 0 50477 9457 No stop slave; reset slave; set global max_relay_log_size=0; @@ -35,26 +35,26 @@ select @@global.max_relay_log_size; 0 start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000008 1283 master-bin.000001 Yes Yes 0 0 50477 1283 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 50477 slave-relay-bin.000008 1283 master-bin.000001 Yes Yes 0 0 50477 1283 No stop slave; reset slave; flush logs; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 No reset slave; start slave; flush logs; create table t1 (a int); show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 50535 slave-relay-bin.000009 62 master-bin.000001 Yes Yes 0 0 50535 62 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 50535 slave-relay-bin.000009 62 master-bin.000001 Yes Yes 0 0 50535 62 No flush logs; drop table t1; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 50583 slave-relay-bin.000010 52 master-bin.000001 Yes Yes 0 0 50583 52 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 50583 slave-relay-bin.000010 52 master-bin.000001 Yes Yes 0 0 50583 52 No flush logs; show master status; File Position Binlog_do_db Binlog_ignore_db diff --git a/mysql-test/r/rpl_openssl.result b/mysql-test/r/rpl_openssl.result index 43cf6bf8176..f6c084d5a71 100644 --- a/mysql-test/r/rpl_openssl.result +++ b/mysql-test/r/rpl_openssl.result @@ -20,11 +20,11 @@ t 1 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 289 slave-relay-bin.000001 64 master-bin.000001 Yes Yes 0 0 289 64 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem +127.0.0.1 replssl MASTER_MYPORT 1 master-bin.000001 289 slave-relay-bin.000001 108 master-bin.000001 Yes Yes 0 0 289 108 Yes MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem stop slave; change master to master_user='root',master_password='', master_ssl=0; start slave; drop table t1; show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 337 slave-relay-bin.000001 52 master-bin.000001 Yes Yes 0 0 337 52 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem +127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 337 slave-relay-bin.000001 96 master-bin.000001 Yes Yes 0 0 337 96 No MYSQL_TEST_DIR/std_data/cacert.pem MYSQL_TEST_DIR/std_data/client-cert.pem MYSQL_TEST_DIR/std_data/client-key.pem diff --git a/mysql-test/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result index 239c4158410..a0750a57260 100644 --- a/mysql-test/r/rpl_reset_slave.result +++ b/mysql-test/r/rpl_reset_slave.result @@ -5,18 +5,18 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 No stop slave; change master to master_user='test'; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 test MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 79 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 test MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 79 4 No reset slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 No start slave; show slave status; -Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 +Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key +127.0.0.1 root MASTER_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 No diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 0d9de8dc4c9..c472b313365 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -81,7 +81,7 @@ a testing temporary tables part 2 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Replicate_do_table Replicate_ignore_table Replicate_wild_do_table Replicate_wild_ignore_table Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -127.0.0.1 root MASTER_PORT 60 master-bin.000006 2886 slave-relay-bin.000001 7891 master-bin.000006 Yes Yes 0 0 2886 7891 No +127.0.0.1 root MASTER_PORT 60 master-bin.000004 2886 slave-relay-bin.000001 7891 master-bin.000004 Yes Yes 0 0 2886 7891 No lock tables t3 read; select count(*) from t3 where n >= 4; count(*) -- cgit v1.2.1 From 0e2f62640500d2d8c0acfbcdc91f207b8457da48 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Sep 2003 14:37:06 +0300 Subject: fixed string parameter assugnment (coping instead of asigning pointer to buffer) (BUG#1115) fixed test_field_misc (UTF variable value) sql/item.cc: added debug informetion fixed string parameter assugnment (coping instead of asigning pointer to buffer) tests/client_test.c: test for BUG#1115 fixed test_field_misc (UTF variable value) --- sql/item.cc | 31 +++++++++++++------ tests/client_test.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 12 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 0ea2231ca4b..96cfc335e5e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -489,27 +489,38 @@ String *Item_null::val_str(String *str) /* Item_param related */ void Item_param::set_null() -{ - maybe_null=null_value=1; +{ + DBUG_ENTER("Item_param::set_null"); + maybe_null= null_value= 1; + DBUG_VOID_RETURN; } void Item_param::set_int(longlong i) -{ - int_value=(longlong)i; - item_type = INT_ITEM; +{ + DBUG_ENTER("Item_param::set_int"); + int_value= (longlong)i; + item_type= INT_ITEM; + DBUG_PRINT("info", ("integer: %lld", int_value)); + DBUG_VOID_RETURN; } void Item_param::set_double(double value) -{ +{ + DBUG_ENTER("Item_param::set_double"); real_value=value; - item_type = REAL_ITEM; + item_type= REAL_ITEM; + DBUG_PRINT("info", ("double: %lg", real_value)); + DBUG_VOID_RETURN; } void Item_param::set_value(const char *str, uint length) -{ - str_value.set(str,length,default_charset()); - item_type = STRING_ITEM; +{ + DBUG_ENTER("Item_param::set_value"); + str_value.copy(str,length,default_charset()); + item_type= STRING_ITEM; + DBUG_PRINT("info", ("string: %s", str_value.ptr())); + DBUG_VOID_RETURN; } diff --git a/tests/client_test.c b/tests/client_test.c index 6aeb865aa20..46a272f2acb 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -1717,7 +1717,7 @@ static void test_select() rc = mysql_commit(mysql); myquery(rc); - /* now insert the second row, and rollback the transaction */ + /* now insert the second row, and rollback the transaction */ rc = mysql_query(mysql,"INSERT INTO test_select VALUES(20,'mysql')"); myquery(rc); @@ -1755,6 +1755,89 @@ static void test_select() mysql_stmt_close(stmt); } +/* + test BUG#1115 (incorrect string parameter value allocation) +*/ +static void test_bug1115() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND bind[1]; + ulong length[1]; + char szData[11]; + int nData=1; + + myheader("test_bug1115"); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_select(\ +session_id char(9) NOT NULL, \ + a int(8) unsigned NOT NULL, \ + b int(5) NOT NULL, \ + c int(5) NOT NULL, \ + d datetime NOT NULL)"); + myquery(rc); + rc = mysql_query(mysql,"INSERT INTO test_select VALUES (\"abc\",1,2,3,2003-08-30), (\"abd\",1,2,3,2003-08-30), (\"abf\",1,2,3,2003-08-30), (\"abg\",1,2,3,2003-08-30), (\"abh\",1,2,3,2003-08-30), (\"abj\",1,2,3,2003-08-30), (\"abk\",1,2,3,2003-08-30), (\"abl\",1,2,3,2003-08-30), (\"abq\",1,2,3,2003-08-30), (\"abw\",1,2,3,2003-08-30), (\"abe\",1,2,3,2003-08-30), (\"abr\",1,2,3,2003-08-30), (\"abt\",1,2,3,2003-08-30), (\"aby\",1,2,3,2003-08-30), (\"abu\",1,2,3,2003-08-30), (\"abi\",1,2,3,2003-08-30), (\"abo\",1,2,3,2003-08-30), (\"abp\",1,2,3,2003-08-30), (\"abz\",1,2,3,2003-08-30), (\"abx\",1,2,3,2003-08-30)"); + myquery(rc); + + strmov(query,"SELECT * FROM test_select WHERE session_id = ?"); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,1); + + strmov(szData,(char *)"abc"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 1); + + strmov(szData,(char *)"venu"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 4; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 0); + + strmov(szData,(char *)"abc"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 1); + + mysql_stmt_close(stmt); +} /******************************************************** * to test simple select show * @@ -5896,7 +5979,7 @@ static void test_field_misc() "@@table_type","", /* field and its org name */ MYSQL_TYPE_STRING, /* field type */ "", "", /* table and its org name */ - "",type_length,0); /* db name, length */ + "",type_length*3,0); /* db name, length */ mysql_free_result(result); mysql_stmt_close(stmt); @@ -7814,6 +7897,7 @@ int main(int argc, char **argv) test_fetch_column(); /* to test mysql_fetch_column */ test_sqlmode(); /* test for SQL_MODE */ test_ts(); /* test for timestamp BR#819 */ + test_bug1115(); /* BUG#1115 */ end_time= time((time_t *)0); total_time+= difftime(end_time, start_time); -- cgit v1.2.1 From 2d7b48987621f20a57487d460d3bd77be4f254d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Sep 2003 19:56:55 +0300 Subject: fixed BUG#1180 (changing WHERE clause of prepared statements by optimisation) sql/item.h: constructor and method for aloning AND/OR structure of WHERE clause sql/item_cmpfunc.cc: constructor and method for aloning AND/OR structure of WHERE clause sql/item_cmpfunc.h: constructor and method for aloning AND/OR structure of WHERE clause sql/item_func.cc: constructor for aloning AND/OR structure of WHERE clause sql/item_func.h: constructor for aloning AND/OR structure of WHERE clause sql/sql_lex.cc: field for saving WHERE root sql/sql_lex.h: field for saving WHERE root sql/sql_prepare.cc: saving WHERE root creating new AND/OR structure before executing prepared statement tests/client_test.c: test suite for bug #1180 --- sql/item.h | 6 +++- sql/item_cmpfunc.cc | 25 +++++++++++++++++ sql/item_cmpfunc.h | 33 ++++++++++++++++++---- sql/item_func.cc | 21 ++++++++++++++ sql/item_func.h | 3 ++ sql/sql_lex.cc | 1 + sql/sql_lex.h | 1 + sql/sql_prepare.cc | 23 ++++++++++++++- tests/client_test.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 186 insertions(+), 7 deletions(-) diff --git a/sql/item.h b/sql/item.h index c7eb7fc2c1b..147c350878e 100644 --- a/sql/item.h +++ b/sql/item.h @@ -120,6 +120,9 @@ public: Constructor used by Item_field, Item_ref & agregate (sum) functions. Used for duplicating lists in processing queries with temporary tables + Also it used for Item_cond_and/Item_cond_or for creating + top AND/OR ctructure of WHERE clause to protect it of + optimisation changes in prepared statements */ Item(THD *thd, Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ @@ -184,6 +187,7 @@ public: virtual void save_in_result_field(bool no_conversions) {} virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } + virtual Item *copy_andor_structure(THD *thd) { return this; } virtual Item *real_item() { return this; } virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } @@ -541,7 +545,7 @@ class Item_result_field :public Item /* Item with result field */ public: Field *result_field; /* Save result here */ Item_result_field() :result_field(0) {} - // Constructor used for Item_sum (see Item comment) + // Constructor used for Item_sum/Item_cond_and/or (see Item comment) Item_result_field(THD *thd, Item_result_field &item): Item(thd, item), result_field(item.result_field) {} diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3471ddd30e9..7460c103550 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1549,6 +1549,31 @@ longlong Item_func_bit_and::val_int() return (longlong) (arg1 & arg2); } +Item_cond::Item_cond(THD *thd, Item_cond &item) + :Item_bool_func(thd, item), + abort_on_null(item.abort_on_null), + and_tables_cache(item.and_tables_cache) +{ + /* + here should be following text: + + List_iterator_fast li(item.list); + while(Item *it= li++) + list.push_back(it); + + but it do not need, + because this constructor used only for AND/OR and + argument list will be copied by copy_andor_arguments call + */ + +} + +void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) +{ + List_iterator_fast li(item->list); + while(Item *it= li++) + list.push_back(it->copy_andor_structure(thd)); +} bool Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9379df84199..f8104491978 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -82,6 +82,7 @@ public: Item_bool_func() :Item_int_func() {} Item_bool_func(Item *a) :Item_int_func(a) {} Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} + Item_bool_func(THD *thd, Item_bool_func &item) :Item_int_func(thd, item) {} void fix_length_and_dec() { decimals=0; max_length=1; } }; @@ -115,8 +116,8 @@ protected: String tmp_value1,tmp_value2; public: - Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} + Item_bool_func2(Item *a,Item *b) + :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} void fix_length_and_dec(); void set_cmp_func() { @@ -158,7 +159,7 @@ public: class Item_func_eq :public Item_bool_rowready_func2 { public: - Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; + Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {} longlong val_int(); enum Functype functype() const { return EQ_FUNC; } enum Functype rev_functype() const { return EQ_FUNC; } @@ -791,8 +792,13 @@ protected: public: /* Item_cond() is only used to create top level items */ Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; } - Item_cond(Item *i1,Item *i2) :Item_bool_func(), abort_on_null(0) - { list.push_back(i1); list.push_back(i2); } + Item_cond(Item *i1,Item *i2) + :Item_bool_func(), abort_on_null(0) + { + list.push_back(i1); + list.push_back(i2); + } + Item_cond(THD *thd, Item_cond &item); ~Item_cond() { list.delete_elements(); } bool add(Item *item) { return list.push_back(item); } bool fix_fields(THD *, struct st_table_list *, Item **ref); @@ -805,6 +811,7 @@ public: void split_sum_func(Item **ref_pointer_array, List &fields); friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); void top_level_item() { abort_on_null=1; } + void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); }; @@ -815,9 +822,17 @@ class Item_cond_and :public Item_cond public: Item_cond_and() :Item_cond() {} Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {} + Item_cond_and(THD *thd, Item_cond_and &item) :Item_cond(thd, item) {} enum Functype functype() const { return COND_AND_FUNC; } longlong val_int(); const char *func_name() const { return "and"; } + Item* copy_andor_structure(THD *thd) + { + Item_cond_and *item; + if((item= new Item_cond_and(thd, *this))) + item->copy_andor_arguments(thd, this); + return item; + } }; class Item_cond_or :public Item_cond @@ -825,10 +840,18 @@ class Item_cond_or :public Item_cond public: Item_cond_or() :Item_cond() {} Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {} + Item_cond_or(THD *thd, Item_cond_or &item) :Item_cond(thd, item) {} enum Functype functype() const { return COND_OR_FUNC; } longlong val_int(); const char *func_name() const { return "or"; } table_map not_null_tables() const { return and_tables_cache; } + Item* copy_andor_structure(THD *thd) + { + Item_cond_or *item; + if((item= new Item_cond_or(thd, *this))) + item->copy_andor_arguments(thd, this); + return item; + } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 4bda8ae78cd..9220fb335e6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -134,6 +134,27 @@ Item_func::Item_func(List &list) set_arguments(list); } +Item_func::Item_func(THD *thd, Item_func &item) + :Item_result_field(thd, item), + allowed_arg_cols(item.allowed_arg_cols), + arg_count(item.arg_count), + used_tables_cache(item.used_tables_cache), + not_null_tables_cache(item.not_null_tables_cache), + const_item_cache(item.const_item_cache) +{ + if (arg_count) + { + if (arg_count <=2) + args= tmp_arg; + else + { + if (!(args=(Item**) thd->alloc(sizeof(Item*)*arg_count))) + return; + } + memcpy((char*) args, (char*) item.args, sizeof(Item*)*arg_count); + } +} + /* Resolve references to table column for a function and it's argument diff --git a/sql/item_func.h b/sql/item_func.h index 7fedbcf48ee..a01c3a37c2f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -104,6 +104,8 @@ public: } } Item_func(List &list); + // Constructor used for Item_cond_and/or (see Item comment) + Item_func(THD *thd, Item_func &item); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ bool fix_fields(THD *,struct st_table_list *, Item **ref); table_map used_tables() const; @@ -196,6 +198,7 @@ public: Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; } Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; } Item_int_func(List &list) :Item_func(list) { max_length=21; } + Item_int_func(THD *thd, Item_int_func &item) :Item_func(thd, item) {} double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d6cfd555c40..80d698dfc26 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -982,6 +982,7 @@ void st_select_lex::init_query() cond_count= with_wild= 0; ref_pointer_array= 0; select_n_having_items= 0; + prep_where= 0; } void st_select_lex::init_select() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 7c39d2fe776..bbf1cd9a130 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -339,6 +339,7 @@ class st_select_lex: public st_select_lex_node public: char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ + Item *prep_where; /* saved WHERE clause for prepared statement processing */ enum olap_type olap; SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ List item_list; /* list of fields & expressions */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 550e4bbe086..3bebdef7738 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -873,11 +873,21 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); + + // save WHERE clause pointers to avoid damaging they by optimisation + for (SELECT_LEX *sl= thd->lex.all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + sl->prep_where= sl->where; + } + if (init_param_items(&stmt)) goto err; + - stmt.mem_root= stmt.thd->mem_root; + stmt.mem_root= stmt.thd->mem_root; tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0); thd->mem_root= thd_root; // restore main mem_root DBUG_RETURN(0); @@ -919,6 +929,17 @@ void mysql_stmt_execute(THD *thd, char *packet) LEX thd_lex= thd->lex; thd->lex= stmt->lex; + + for (SELECT_LEX *sl= stmt->lex.all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + // copy WHERE clause pointers to avoid damaging they by optimisation + if (sl->prep_where) + sl->where= sl->prep_where->copy_andor_structure(thd); + // force allocation new JOIN for this mem_root (for safety) + sl->join= 0; + } init_stmt_execute(stmt); if (stmt->param_count && setup_params_data(stmt)) diff --git a/tests/client_test.c b/tests/client_test.c index 46a272f2acb..c2bc966fee8 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -1839,6 +1839,85 @@ session_id char(9) NOT NULL, \ mysql_stmt_close(stmt); } +/* + test BUG#1180 (optimized away part of WHERE clause) +*/ +static void test_bug1180() +{ + MYSQL_STMT *stmt; + int rc; + MYSQL_BIND bind[1]; + ulong length[1]; + char szData[11]; + int nData=1; + + myheader("test_select_bug"); + + rc = mysql_query(mysql,"DROP TABLE IF EXISTS test_select"); + myquery(rc); + + rc = mysql_query(mysql,"CREATE TABLE test_select(session_id char(9) NOT NULL)"); + myquery(rc); + rc = mysql_query(mysql,"INSERT INTO test_select VALUES (\"abc\")"); + myquery(rc); + + strmov(query,"SELECT * FROM test_select WHERE ?=\"1111\" and session_id = \"abc\""); + stmt = mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + + verify_param_count(stmt,1); + + strmov(szData,(char *)"abc"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 0); + + strmov(szData,(char *)"1111"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 4; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 1); + + strmov(szData,(char *)"abc"); + bind[0].buffer_type=FIELD_TYPE_STRING; + bind[0].buffer=(char *)szData; + bind[0].buffer_length= 10; + bind[0].length= &length[0]; + length[0]= 3; + bind[0].is_null=0; + + rc = mysql_bind_param(stmt,bind); + mystmt(stmt, rc); + + rc = mysql_execute(stmt); + mystmt(stmt, rc); + + myassert(my_process_stmt_result(stmt) == 0); + + mysql_stmt_close(stmt); +} + /******************************************************** * to test simple select show * *********************************************************/ @@ -7898,6 +7977,7 @@ int main(int argc, char **argv) test_sqlmode(); /* test for SQL_MODE */ test_ts(); /* test for timestamp BR#819 */ test_bug1115(); /* BUG#1115 */ + test_bug1180(); /* BUG#1180 */ end_time= time((time_t *)0); total_time+= difftime(end_time, start_time); -- cgit v1.2.1 From 09bbb2e04922c3415754bb7fe9991be2c560cd5e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 10:59:14 +0300 Subject: inserted forgoten ASSERT (BUG#1180) sql/sql_prepare.cc: inserted forgoten ASSERT --- sql/sql_prepare.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3bebdef7738..4abbbcaff1f 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -937,8 +937,7 @@ void mysql_stmt_execute(THD *thd, char *packet) // copy WHERE clause pointers to avoid damaging they by optimisation if (sl->prep_where) sl->where= sl->prep_where->copy_andor_structure(thd); - // force allocation new JOIN for this mem_root (for safety) - sl->join= 0; + DBUG_ASSERT(sl->join == 0); } init_stmt_execute(stmt); -- cgit v1.2.1 From 93c9f9c69ff12d765b4c119c3eee240db97cbea7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 12:19:30 +0400 Subject: Added automatically created SSL certificates from mysql-test/std_data to ignore list. --- .bzrignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.bzrignore b/.bzrignore index 35db3c5d5ba..b28278f83a7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -473,6 +473,7 @@ mysql-test/r/rpl_log.eval mysql-test/r/slave-running.eval mysql-test/r/slave-stopped.eval mysql-test/share/mysql +mysql-test/std_data/*.pem mysql-test/var/* mysql.kdevprj mysql.proj -- cgit v1.2.1 From 4a21b30e47cfb2905ac1e6a3e9a220164067b595 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 11:34:32 +0200 Subject: CHECKSUM TABLE table1, table2, ... [ QUICK | EXTENDED ] myisam/mi_checksum.c: workaround for zlib's crc32 glitch mysql-test/r/show_check.result: results updated mysys/checksum.c: switching to crc32 as a checksum algorithm --- myisam/mi_checksum.c | 2 +- mysql-test/r/innodb.result | 25 ++++++++++++++++ mysql-test/r/myisam.result | 23 +++++++++++++-- mysql-test/r/show_check.result | 2 +- mysql-test/t/innodb.test | 12 ++++++++ mysql-test/t/myisam.test | 13 ++++++++- mysys/checksum.c | 4 ++- sql/mysql_priv.h | 3 +- sql/sql_parse.cc | 2 +- sql/sql_table.cc | 66 ++++++++++++++++++++++++++++++++---------- sql/sql_yacc.yy | 14 ++++++--- 11 files changed, 138 insertions(+), 28 deletions(-) diff --git a/myisam/mi_checksum.c b/myisam/mi_checksum.c index 982f77ee81f..cdbb634c5ff 100644 --- a/myisam/mi_checksum.c +++ b/myisam/mi_checksum.c @@ -50,7 +50,7 @@ ha_checksum mi_checksum(MI_INFO *info, const byte *buf) pos=buf; break; } - crc=my_checksum(crc, pos, length); + crc=my_checksum(crc, pos ? pos : "", length); } return crc; } diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 20cc50dcc61..e1a03b051ce 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1341,3 +1341,28 @@ ERROR HY000: Table storage engine for 't1' doesn't have this option select * from t1; c1 c2 stamp drop table t1; +create table t1 (a int, b varchar(200), c text not null) checksum=1 type=myisam; +create table t2 (a int, b varchar(200), c text not null) checksum=0 type=innodb; +create table t3 (a int, b varchar(200), c text not null) checksum=1 type=innodb; +insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); +insert t2 select * from t1; +insert t3 select * from t1; +checksum table t1, t2, t3, t4 quick; +Table Checksum +test.t1 968604391 +test.t2 NULL +test.t3 NULL +test.t4 NULL +checksum table t1, t2, t3, t4; +Table Checksum +test.t1 968604391 +test.t2 968604391 +test.t3 968604391 +test.t4 NULL +checksum table t1, t2, t3, t4 extended; +Table Checksum +test.t1 968604391 +test.t2 968604391 +test.t3 968604391 +test.t4 NULL +drop table t1,t2,t3; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index fd9ff2c90cf..ece89ca282d 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -394,6 +394,23 @@ id select_type table type possible_keys key key_len ref rows Extra drop table t1,t2; CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) TYPE=MyISAM; ERROR 42000: This version of MySQL doesn't yet support 'RTREE INDEX' -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' +create table t1 (a int, b varchar(200), c text not null) checksum=1; +create table t2 (a int, b varchar(200), c text not null) checksum=0; +insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); +insert t2 select * from t1; +checksum table t1, t2, t3 quick; +Table Checksum +test.t1 968604391 +test.t2 NULL +test.t3 NULL +checksum table t1, t2, t3; +Table Checksum +test.t1 968604391 +test.t2 968604391 +test.t3 NULL +checksum table t1, t2, t3 extended; +Table Checksum +test.t1 968604391 +test.t2 968604391 +test.t3 NULL +drop table t1,t2; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 201d1b541ae..682c48c9c55 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -43,7 +43,7 @@ wait_timeout 28800 show variables like "this_doesn't_exists%"; Variable_name Value show table status from test like "this_doesn't_exists%"; -Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Charset Create_options Comment +Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Charset Checksum Create_options Comment show databases; Database mysql diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index cd3a5693535..72a791b263c 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -920,3 +920,15 @@ replace delayed into t1 (c1, c2) values ( "text1","12"),( "text2","13"),( "text select * from t1; drop table t1; +create table t1 (a int, b varchar(200), c text not null) checksum=1 type=myisam; +create table t2 (a int, b varchar(200), c text not null) checksum=0 type=innodb; +create table t3 (a int, b varchar(200), c text not null) checksum=1 type=innodb; +insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); +insert t2 select * from t1; +insert t3 select * from t1; +checksum table t1, t2, t3, t4 quick; +checksum table t1, t2, t3, t4; +checksum table t1, t2, t3, t4 extended; +#show table status; +drop table t1,t2,t3; + diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 80d46d1ef0c..2bcc5dd7514 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -360,4 +360,15 @@ drop table t1,t2; CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) TYPE=MyISAM; # INSERT INTO t1 VALUES (1,1),(1,1); # DELETE FROM rt WHERE a<1; -DROP TABLE IF EXISTS t1; +# DROP TABLE IF EXISTS t1; + +create table t1 (a int, b varchar(200), c text not null) checksum=1; +create table t2 (a int, b varchar(200), c text not null) checksum=0; +insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); +insert t2 select * from t1; +checksum table t1, t2, t3 quick; +checksum table t1, t2, t3; +checksum table t1, t2, t3 extended; +#show table status; +drop table t1,t2; + diff --git a/mysys/checksum.c b/mysys/checksum.c index 2ae139b81c3..664e768ef4e 100644 --- a/mysys/checksum.c +++ b/mysys/checksum.c @@ -30,9 +30,11 @@ ha_checksum my_checksum(ha_checksum crc, const byte *pos, uint length) { - const byte *end=pos+length; +/* const byte *end=pos+length; for ( ; pos != end ; pos++) crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8)); return crc; +*/ + return (ha_checksum)crc32((uint)crc, (const uchar *)pos, length); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9834d169ac4..5913bee6d0a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -398,7 +398,8 @@ bool check_global_access(THD *thd, ulong want_access); int mysql_backup_table(THD* thd, TABLE_LIST* table_list); int mysql_restore_table(THD* thd, TABLE_LIST* table_list); -int mysql_checksum_table(THD* thd, TABLE_LIST* table_list); +int mysql_checksum_table(THD* thd, TABLE_LIST* table_list, + HA_CHECK_OPT* check_opt); int mysql_check_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); int mysql_repair_table(THD* thd, TABLE_LIST* table_list, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0e344756b18..fb74ca7dd71 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2269,7 +2269,7 @@ mysql_execute_command(THD *thd) if (check_db_used(thd,tables) || check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables)) goto error; /* purecov: inspected */ - res = mysql_checksum_table(thd, tables); + res = mysql_checksum_table(thd, tables, &lex->check_opt); break; } case SQLCOM_REPAIR: diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d63a15c13a8..48a99cfaad5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -350,10 +350,10 @@ static int sort_keys(KEY *a, KEY *b) fields List of fields to create keys List of keys to create tmp_table Set to 1 if this is an internal temporary table - (From ALTER TABLE) + (From ALTER TABLE) no_log Don't log the query to binary log. - DESCRIPTION + DESCRIPTION If one creates a temporary table, this is automaticly opened no_log is needed for the case of CREATE ... SELECT, @@ -672,11 +672,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, /* Make SPATIAL to be RTREE by default SPATIAL only on BLOB or at least BINARY, this - actually should be replaced by special GEOM type + actually should be replaced by special GEOM type in near future when new frm file is ready checking for proper key parts number: */ - + if (key_info->flags == HA_SPATIAL) { if (key_info->key_parts != 1) @@ -699,7 +699,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, MYF(0), "RTREE INDEX"); DBUG_RETURN(-1); } - + List_iterator cols(key->columns); for (uint column_nr=0 ; (column=cols++) ; column_nr++) { @@ -745,9 +745,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if (!column->length ) { - /* + /* BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case - Lately we'll extend this code to support more dimensions + Lately we'll extend this code to support more dimensions */ column->length=4*sizeof(double); } @@ -797,7 +797,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { } else if (column->length > length || - ((f_is_packed(sql_field->pack_flag) || + ((f_is_packed(sql_field->pack_flag) || ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && (key_info->flags & HA_NOSAME))) && column->length != length)) @@ -2588,7 +2588,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, DBUG_RETURN(error > 0 ? -1 : 0); } -int mysql_checksum_table(THD* thd, TABLE_LIST* tables) +int mysql_checksum_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *check_opt) { TABLE_LIST *table; List field_list; @@ -2608,9 +2608,10 @@ int mysql_checksum_table(THD* thd, TABLE_LIST* tables) char table_name[NAME_LEN*2+2]; char* db = (table->db) ? table->db : thd->db; bool fatal_error=0; + TABLE *t; strxmov(table_name,db ? db : "",".",table->real_name,NullS); - table->table = open_ltable(thd, table, TL_READ_NO_INSERT); + t=table->table = open_ltable(thd, table, TL_READ_NO_INSERT); #ifdef EMBEDDED_LIBRARY thd->net.last_errno= 0; // these errors shouldn't get client #endif @@ -2618,19 +2619,54 @@ int mysql_checksum_table(THD* thd, TABLE_LIST* tables) protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); - if (!table->table) + if (!t) { protocol->store_null(); thd->net.last_error[0]=0; } else { - table->table->pos_in_table_list= table; + t->pos_in_table_list= table; - if (table->table->file->table_flags() & HA_HAS_CHECKSUM) - protocol->store((ulonglong)table->table->file->checksum()); - else + if (t->file->table_flags() & HA_HAS_CHECKSUM && + !(check_opt->flags & T_EXTEND)) + protocol->store((ulonglong)t->file->checksum()); + else if (!(t->file->table_flags() & HA_HAS_CHECKSUM) && + check_opt->flags & T_QUICK) protocol->store_null(); + else + { + /* calculating table's checksum */ + ha_checksum crc=0; + if (t->file->rnd_init(1)) + protocol->store_null(); + else + { + while (!t->file->rnd_next(t->record[0])) + { + ha_checksum row_crc=0; + if (t->record[0] != t->field[0]->ptr) + row_crc=my_checksum(row_crc, t->record[0], + t->field[0]->ptr - t->record[0]); + + for (uint i=0; i < t->fields; i++ ) + { + Field *f=t->field[i]; + if (f->type() == FIELD_TYPE_BLOB) + { + String tmp; + f->val_str(&tmp,&tmp); + row_crc=my_checksum(row_crc, tmp.ptr(), tmp.length()); + } + else + row_crc=my_checksum(row_crc, f->ptr, f->pack_length()); + } + + crc+=row_crc; + } + protocol->store((ulonglong)crc); + } + } #ifdef EMBEDDED_LIBRARY thd->net.last_errno= 0; // these errors shouldn't get client #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9be2b21debc..a63d70620fd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1080,7 +1080,7 @@ opt_select_from: | select_from select_lock_type; udf_func_type: - /* empty */ { $$ = UDFTYPE_FUNCTION; } + /* empty */ { $$ = UDFTYPE_FUNCTION; } | AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; }; udf_type: @@ -1547,7 +1547,7 @@ opt_ident: opt_component: /* empty */ { $$.str= 0; $$.length= 0; } | '.' ident { $$=$2; }; - + string_list: text_string { Lex->interval_list.push_back($1); } | string_list ',' text_string { Lex->interval_list.push_back($3); }; @@ -1760,10 +1760,16 @@ checksum: LEX *lex=Lex; lex->sql_command = SQLCOM_CHECKSUM; } - table_list - {} + table_list opt_checksum_type + {} ; +opt_checksum_type: + /* nothing */ { Lex->check_opt.flags= 0; } + | QUICK { Lex->check_opt.flags= T_QUICK; } + | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; } + ; + repair: REPAIR opt_no_write_to_binlog table_or_tables { -- cgit v1.2.1 From 369ab1352a3708f84aebd9c30ab3cab26ab0eaf3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 11:37:59 +0200 Subject: making InnoDB to return the row exactly the same (bytewise) as it was written to it --- innobase/row/row0sel.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 97a69f76eaa..362b632a65e 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2069,7 +2069,7 @@ row_sel_store_mysql_rec( ulint len; byte* blob_buf; ulint i; - + ut_ad(prebuilt->mysql_template); if (prebuilt->blob_heap != NULL) { @@ -2077,9 +2077,9 @@ row_sel_store_mysql_rec( prebuilt->blob_heap = NULL; } - /* Mark all columns as not SQL NULL */ + /* Mark all columns as SQL NULL */ - memset(mysql_rec, '\0', prebuilt->null_bitmap_len); + memset(mysql_rec, 255, prebuilt->null_bitmap_len); for (i = 0; i < prebuilt->n_template; i++) { @@ -2134,16 +2134,21 @@ row_sel_store_mysql_rec( data = blob_buf; } - + row_sel_field_store_in_mysql_format( mysql_rec + templ->mysql_col_offset, templ->mysql_col_len, data, len, templ->type, templ->is_unsigned); if (extern_field_heap) { - mem_heap_free(extern_field_heap); + mem_heap_free(extern_field_heap); extern_field_heap = NULL; - } + } + + if (templ->mysql_null_bit_mask) { + mysql_rec[templ->mysql_null_byte_offset] &= + ~(byte) (templ->mysql_null_bit_mask); + } } else { /* MySQL seems to assume the field for an SQL NULL value is set to zero. Not taking this into account @@ -2151,19 +2156,13 @@ row_sel_store_mysql_rec( bug number 154 in the MySQL bug database: GROUP BY and DISTINCT could treat NULL values inequal. */ - memset(mysql_rec + templ->mysql_col_offset, '\0', + memset(mysql_rec + templ->mysql_col_offset, + ((templ->type == DATA_VARCHAR || + templ->type == DATA_VARMYSQL || + templ->type == DATA_BINARY) ? ' ' : '\0'), templ->mysql_col_len); - - if (!templ->mysql_null_bit_mask) { - fprintf(stderr, -"InnoDB: Error: trying to return an SQL NULL field in a non-null\n" -"innoDB: column! Table name %s\n", prebuilt->table->name); - } else { - mysql_rec[templ->mysql_null_byte_offset] |= - (byte) (templ->mysql_null_bit_mask); - } } - } + } return(TRUE); } -- cgit v1.2.1 From d42b4eeb1dafcf6760b4d88bab0f68dad908b159 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 16:43:41 +0400 Subject: post-merge fixes mysql-test/r/func_crypt.result: _dig_vec converted lowercase sql/slave.cc: post-merge fix --- mysql-test/r/func_crypt.result | 12 ++++++------ sql/slave.cc | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index bd4c6d41d39..5ee0f0f3e93 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -3,7 +3,7 @@ length(encrypt('foo', 'ff')) <> 0 1 select password('abc'); password('abc') -*0d3ced9bec10a777aec23ccc353a8c08a633045e +*0D3CED9BEC10A777AEC23CCC353A8C08A633045E select password(''); password('') @@ -15,7 +15,7 @@ old_password('') select password('gabbagabbahey'); password('gabbagabbahey') -*b0f99d2963660dd7e16b751ec9ee2f17b6a68fa6 +*B0F99D2963660DD7E16B751EC9EE2F17B6A68FA6 select old_password('idkfa'); old_password('idkfa') 5c078dc54ca0fcca @@ -43,7 +43,7 @@ old_password('') select password('idkfa'); password('idkfa') -*b669c9dac3aa6f2254b03cdef8dfdd6b2d1054ba +*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA select old_password('idkfa'); old_password('idkfa') 5c078dc54ca0fcca @@ -64,13 +64,13 @@ old_password('idkfa') set old_passwords=off; select password('idkfa '); password('idkfa ') -*2dc31d90647b4c1abc9231563d2236e96c9a2db2 +*2DC31D90647B4C1ABC9231563D2236E96C9A2DB2 select password('idkfa'); password('idkfa') -*b669c9dac3aa6f2254b03cdef8dfdd6b2d1054ba +*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA select password(' idkfa'); password(' idkfa') -*12b099e56bb7fe8d43c78fd834a9d1d11178d045 +*12B099E56BB7FE8D43C78FD834A9D1D11178D045 select old_password('idkfa'); old_password('idkfa') 5c078dc54ca0fcca diff --git a/sql/slave.cc b/sql/slave.cc index c10f0417585..dd25fe5e75e 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1554,7 +1554,7 @@ void init_master_info_with_options(MASTER_INFO* mi) if (master_user) strmake(mi->user, master_user, sizeof(mi->user) - 1); if (master_password) - strmake(mi->password, master_password, HASH_PASSWORD_LENGTH); + strmake(mi->password, master_password, MAX_PASSWORD_LENGTH); mi->port = master_port; mi->connect_retry = master_connect_retry; -- cgit v1.2.1 From b74332ec6bd0882a5f328236fdc2a52b395ae2f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 17:29:51 +0400 Subject: fixed after-merge bug in CHANG_USER command sql/sql_parse.cc: fixed after-merge bug in CHANGE_USER command --- sql/sql_parse.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 383b6b0f581..0a9a57d86bb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1192,14 +1192,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ? *passwd++ : strlen(passwd); db+= passwd_len + 1; - /* Convert database name to utf8 */ - String convdb; - convdb.copy(db, strlen(db), thd->variables.character_set_client, - system_charset_info); - db= convdb.c_ptr(); - - - /* Small check for incomming packet */ if ((uint) ((uchar*) db - net->read_pos) > packet_length) { @@ -1207,6 +1199,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } + /* Convert database name to utf8 */ + String convdb; + convdb.copy(db, strlen(db), thd->variables.character_set_client, + system_charset_info); + db= convdb.c_ptr(); + /* Save user and privileges */ uint save_master_access= thd->master_access; uint save_db_access= thd->db_access; -- cgit v1.2.1 From ff458939239b11cb88f6eef9c34c18276c3c87b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 18:07:00 +0400 Subject: Monty explanation for net_store_length(uint) put to the comment --- sql/protocol.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index 99d1e03c8a7..d1eb3460fc8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -371,7 +371,13 @@ bool send_old_password_request(THD *thd) #endif /* EMBEDDED_LIBRARY */ /* - Faster net_store_length when we know length is a 32 bit integer + Faster net_store_length when we know that length is less than 65536. + We keep a separate version for that range because it's widely used in + libmysql. + uint is used as agrument type because of MySQL type conventions: + uint for 0..65536 + ulong for 0..4294967296 + ulonglong for bigger numbers. */ char *net_store_length(char *pkg, uint length) -- cgit v1.2.1 From d8572f2447c33fd46737aac9f7eaaa44fc8f1788 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 16:31:01 +0200 Subject: C cleanups --- include/mysql_com.h | 2 +- libmysql/libmysql.c | 5 +++-- sql/password.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index 8d61641cf29..b8dc877f125 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -319,7 +319,7 @@ void randominit(struct rand_struct *, unsigned long seed1, double my_rnd(struct rand_struct *); void create_random_string(char *to, uint length, struct rand_struct *rand_st); -void hash_password(ulong *to, const char *password, uint password_len); +void hash_password(unsigned long *to, const char *password, uint password_len); void make_scrambled_password_323(char *to, const char *password); void scramble_323(char *to, const char *message, const char *password); my_bool check_scramble_323(const char *, const char *message, diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 67576a961ef..0a9e1114fc5 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -594,6 +594,8 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, const char *passwd, const char *db) { char buff[512],*end=buff; + NET *net= &mysql->net; + ulong pkt_length; DBUG_ENTER("mysql_change_user"); if (!user) @@ -627,8 +629,7 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user, /* Write authentication package */ simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); - NET *net= &mysql->net; - ulong pkt_length= net_safe_read(mysql); + pkt_length= net_safe_read(mysql); if (pkt_length == packet_error) goto error; diff --git a/sql/password.c b/sql/password.c index 16227aab611..9f4910d8c60 100644 --- a/sql/password.c +++ b/sql/password.c @@ -170,15 +170,15 @@ void scramble_323(char *to, const char *message, const char *password) if (password && password[0]) { - char *to_start=to; + char extra, *to_start=to; + const char *message_end= message + SCRAMBLE_LENGTH_323; hash_password(hash_pass,password, strlen(password)); hash_password(hash_message, message, SCRAMBLE_LENGTH_323); randominit(&rand_st,hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]); - const char *message_end= message + SCRAMBLE_LENGTH_323; for (; message < message_end; message++) *to++= (char) (floor(my_rnd(&rand_st)*31)+64); - char extra=(char) (floor(my_rnd(&rand_st)*31)); + extra=(char) (floor(my_rnd(&rand_st)*31)); while (to_start != to) *(to_start++)^=extra; } -- cgit v1.2.1 From 7efa0ee1d4ca5ec469669e2b61276e75d126f01c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Sep 2003 21:52:42 +0400 Subject: fixed bug - check_user shall not be included into the embedded library. --- sql/sql_parse.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a05b98e85ba..a5d83c2951d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -176,6 +176,7 @@ end: } +#ifndef EMBEDDED_LIBRARY /* Check if user exist and password supplied is correct. @@ -351,6 +352,9 @@ static int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } +#endif // EMBEDDED_LIBRARY + + /* Check for maximum allowable user connections, if the mysqld server is started with corresponding variable that is greater then 0. -- cgit v1.2.1 From d89b2a9f1d23fe6e3cc877c23b3235b0a0782323 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Sep 2003 06:44:16 +0600 Subject: BUG correct bug 1085 (a problem with min/max functions) add tests of bugs 833,836,1085 mysql-test/r/func_gconcat.result: add tests of bugs 833, 836, 1085 mysql-test/t/func_gconcat.test: add tests of bugs #833, 836, 1085 sql/item_sum.cc: merge sql/item_sum.h: correct bug 1085 --- mysql-test/r/func_gconcat.result | 18 ++++++++++++++++++ mysql-test/t/func_gconcat.test | 21 +++++++++++++++++++++ sql/item_sum.cc | 8 ++++---- sql/item_sum.h | 4 ++-- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index a4493e7c95c..5c3c2f10000 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -167,6 +167,11 @@ t2.URL_ID = t1.URL_ID group by REQ_ID; REQ_ID URL 1 X 5 X,X,X +select REQ_ID, Group_Concat(URL) as URL, Min(t1.URL_ID) urll, +Max(t1.URL_ID) urlg from t1, t2 where t2.URL_ID = t1.URL_ID group by REQ_ID; +REQ_ID URL urll urlg +1 X 4 4 +5 X,X,X 4 5 drop table t1; drop table t2; create table t1 (id int, name varchar(16)); @@ -178,3 +183,16 @@ select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') a with distinct: cutoff at length of shortname 1:longername,1:evenlongername drop table t1; +create table t1(id int); +create table t2(id int); +insert into t1 values(0),(1); +select group_concat(t1.id) FROM t1,t2; +group_concat(t1.id) +NULL +drop table t1; +drop table t2; +create table t1 (bar varchar(32)); +insert into t1 values('test'),('test2'); +select * from t1 having group_concat(bar)=''; +bar +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index f426f9ca4ee..b10f6d2af21 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -91,6 +91,11 @@ insert into t2 values (1,4), (5,4), (5,5); --replace_result www.help.com X www.host.com X www.google.com X select REQ_ID, Group_Concat(URL) as URL from t1, t2 where t2.URL_ID = t1.URL_ID group by REQ_ID; +# check min/max function +--replace_result www.help.com X www.host.com X www.google.com X +select REQ_ID, Group_Concat(URL) as URL, Min(t1.URL_ID) urll, +Max(t1.URL_ID) urlg from t1, t2 where t2.URL_ID = t1.URL_ID group by REQ_ID; + drop table t1; drop table t2; @@ -99,3 +104,19 @@ insert into t1 values (1,'longername'),(1,'evenlongername'); select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; drop table t1; + +# check zero rows +create table t1(id int); +create table t2(id int); +insert into t1 values(0),(1); +select group_concat(t1.id) FROM t1,t2; +drop table t1; +drop table t2; + +# check having +create table t1 (bar varchar(32)); +insert into t1 values('test'),('test2'); +select * from t1 having group_concat(bar)=''; +drop table t1; + + diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 07e62ae35de..814612cfca8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1460,7 +1460,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1, for (uint i= 0; i < item->arg_count_field; i++) { Item *field_item= item->args[i]; - Field *field= field_item->real_item()->tmp_table_field(); + Field *field= field_item->real_item()->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1491,7 +1491,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2) { ORDER *order_item= item->order[i]; Item *item= *order_item->item; - Field *field= item->real_item()->tmp_table_field(); + Field *field= item->real_item()->get_tmp_table_field(); if (field) { uint offset= field->abs_offset; @@ -1542,7 +1542,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), Item *show_item= group_concat_item->args[i]; if (!show_item->const_item()) { - Field *f= show_item->real_item()->tmp_table_field(); + Field *f= show_item->real_item()->get_tmp_table_field(); char *sv= f->ptr; f->ptr= (char *)key + f->abs_offset; String *res= f->val_str(&tmp,&tmp2); @@ -1709,7 +1709,7 @@ bool Item_func_group_concat::add() Item *show_item= args[i]; if (!show_item->const_item()) { - Field *f= show_item->real_item()->tmp_table_field(); + Field *f= show_item->real_item()->get_tmp_table_field(); if (!f->is_null()) { record_is_null= FALSE; diff --git a/sql/item_sum.h b/sql/item_sum.h index 7dca0502cb0..b2377a96833 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -386,8 +386,8 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(THD *thd, Item_sum_hybrid &item): Item_sum(thd, item), value(item.value), tmp_value(item.tmp_value), sum(item.sum), sum_int(item.sum_int), hybrid_type(item.hybrid_type), - cmp_sign(item.cmp_sign), used_table_cache(used_table_cache), - cmp_charset(item.cmp_charset) {} + hybrid_field_type(item.hybrid_field_type),cmp_sign(item.cmp_sign), + used_table_cache(used_table_cache), cmp_charset(item.cmp_charset) {} bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } -- cgit v1.2.1 From 6f607d3aa6e2f59add1ebc4d0045fa73c009b79d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Sep 2003 17:12:20 +0500 Subject: Fix for bug 1176 --- mysql-test/r/derived.result | 8 ++++++++ mysql-test/t/derived.test | 13 +++++++++++++ sql/sql_derived.cc | 2 +- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index f9e52174469..944253bd527 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -196,3 +196,11 @@ drop table t1,t2; SELECT a.x FROM (SELECT 1 AS x) AS a HAVING a.x = 1; x 1 +create table a1 select 1 as a; +select 2 as a from (select * from a1) b; +ERROR 3D000: No Database Selected +use test; +select 2 as a from (select * from a1) b; +a +2 +drop table a1; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index c3edbabcd53..3c735878e46 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -94,3 +94,16 @@ drop table t1,t2; # derived table reference # SELECT a.x FROM (SELECT 1 AS x) AS a HAVING a.x = 1; + +# +# Test for select if database is not selected. +# +# Connect without a database +create table a1 select 1 as a; +connect (con1,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,master.sock); +connection con1; +--error 1046 +select 2 as a from (select * from a1) b; +use test; +select 2 as a from (select * from a1) b; +drop table a1; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 771d68e8462..5d05fea4fe3 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -96,7 +96,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, else res= check_access(thd, SELECT_ACL, any_db); if (res) - DBUG_RETURN(-1); + DBUG_RETURN(1); if (!(res=open_and_lock_tables(thd,tables))) { -- cgit v1.2.1 From 1496610d1cb606fa924c4ec48ac8d7c2ffc03ef7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 6 Sep 2003 18:50:30 +0500 Subject: Fix for LOAD DATA to work with embedded library libmysqld/lib_sql.cc: There's now one common SCRAMBLE_LENGTH sql/sql_load.cc: mysql_load fixed to work with embedded library sql/sql_parse.cc: LOAD DATA enabled for embedded library --- libmysqld/lib_sql.cc | 1 - sql/sql_load.cc | 30 +++++++++++++++++++++++------- sql/sql_parse.cc | 4 ++-- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 05c36f353fd..00ec550273c 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -34,7 +34,6 @@ static char inited, org_my_init_done; #include "../sql/mysqld.cc" #endif -#define SCRAMBLE_LENGTH 8 C_MODE_START #include #include "errmsg.h" diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d030eaf617c..dd6bdf45e82 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -77,9 +77,6 @@ static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, List &fields, READ_INFO &read_info, String &enclosed); - -#ifndef EMBEDDED_LIBRARY - int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, List &fields, enum enum_duplicates handle_duplicates, bool read_file_from_client,thr_lock_type lock_type) @@ -91,7 +88,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, String *field_term=ex->field_term,*escaped=ex->escaped, *enclosed=ex->enclosed; bool is_fifo=0; +#ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; +#endif char *db = table_list->db; // This is never null /* If no current database, use database where table is located */ char *tdb= thd->db ? thd->db : db; @@ -184,6 +183,17 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } else { +#ifdef EMBEDDED_LIBRARY + char *chk_name= ex->file_name; + while ((*chk_name == ' ') || (*chk_name == 't')) + chk_name++; + if (*chk_name == FN_CURLIB) + { + sprintf(name, "%s%s", mysql_data_home, ex->file_name); + unpack_filename(name, name); + } + else +#endif /*EMBEDDED_LIBRARY*/ unpack_filename(name,ex->file_name); #if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__) MY_STAT stat_info; @@ -225,6 +235,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, DBUG_RETURN(-1); // Can't allocate buffers } +#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { lf_info.thd = thd; @@ -238,6 +249,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, lf_info.log_delayed= log_delayed; read_info.set_io_cache_arg((void*) &lf_info); } +#endif /*!EMBEDDED_LIBRARY*/ + restore_record(table,default_values); thd->count_cuted_fields=1; /* calc cuted fields */ @@ -293,6 +306,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { if (transactional_table) ha_autocommit_or_rollback(thd,error); +#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { if (lf_info.wrote_create_file) @@ -315,6 +329,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, mysql_bin_log.write(&d); } } +#endif /*!EMBEDDED_LIBRARY*/ error= -1; // Error on read goto err; } @@ -327,6 +342,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (!log_delayed) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; +#ifndef EMBEDDED_LIBRARY if (mysql_bin_log.is_open()) { if (opt_old_rpl_compat) @@ -348,6 +364,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } } } +#endif /*!EMBEDDED_LIBRARY*/ if (transactional_table) error=ha_autocommit_or_rollback(thd,error); err: @@ -359,8 +376,6 @@ err: DBUG_RETURN(error); } -#endif /* EMBEDDED_LIBRARY */ - /**************************************************************************** ** Read of rows of fixed size + optional garage + optonal newline ****************************************************************************/ @@ -640,11 +655,12 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, mysys/mf_iocache.c. So we work around the problem with a manual assignment */ + need_end_io_cache = 1; + +#ifndef EMBEDDED_LIBRARY if (get_it_from_net) cache.read_function = _my_b_net_read; - need_end_io_cache = 1; -#ifndef EMBEDDED_LIBRARY if (!opt_old_rpl_compat && mysql_bin_log.is_open()) cache.pre_read = cache.pre_close = (IO_CACHE_CALLBACK) log_loaded_block; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a5d83c2951d..7e520aabf21 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2755,7 +2755,7 @@ mysql_execute_command(THD *thd) case SQLCOM_CHANGE_DB: mysql_change_db(thd,select_lex->db); break; -#ifndef EMBEDDED_LIBRARY + case SQLCOM_LOAD: { uint privilege= (lex->duplicates == DUP_REPLACE ? @@ -2782,7 +2782,7 @@ mysql_execute_command(THD *thd) lex->duplicates, (bool) lex->local_file, lex->lock_option); break; } -#endif /* EMBEDDED_LIBRARY */ + case SQLCOM_SET_OPTION: if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) || (res= open_and_lock_tables(thd,tables)))) -- cgit v1.2.1 From 57c9756b6993d1c21bfeab67e0944b541c24a408 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 7 Sep 2003 20:35:10 +0300 Subject: fixed row union processing mysql-test/r/subselect.result: row union test mysql-test/t/subselect.test: row union test --- mysql-test/r/subselect.result | 8 ++++++++ mysql-test/t/subselect.test | 10 ++++++++++ sql/item_subselect.cc | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index dd8aeba8563..625fb9f9c29 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1361,3 +1361,11 @@ userid pmtotal pmnew calc_total calc_new 1 0 0 9 3 2 0 0 4 2 drop table t1, t2; +create table t1 (s1 char(5)); +select (select 'a','b' from t1 union select 'a','b' from t1) from t1; +ERROR 21000: Cardinality error (more/less than 1 columns) +insert into t1 values ('tttt'); +select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); +s1 +tttt +drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index c9dba498428..4b8d63b681e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -922,3 +922,13 @@ insert into t2 values(1,0,0),(2,0,0); insert into t1 values(1,0),(1,0),(1,0),(1,12),(1,15),(1,123),(1,12312),(1,12312),(1,123),(2,0),(2,0),(2,1),(2,2); select userid,pmtotal,pmnew, (select count(rd) from t1 where toid=t2.userid) calc_total, (select count(rd) from t1 where rd=0 and toid=t2.userid) calc_new from t2 where userid in (select distinct toid from t1); drop table t1, t2; + +# +# row union +# +create table t1 (s1 char(5)); +-- error 1240 +select (select 'a','b' from t1 union select 'a','b' from t1) from t1; +insert into t1 values ('tttt'); +select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); +drop table t1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d383bf65c88..79366086a8d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -846,7 +846,7 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) SELECT_LEX *sl= unit->first_select(); bool fake= 0; res_type= set_row(sl, item, row, &fake); - for (sl= sl->next_select(); sl; sl->next_select()) + for (sl= sl->next_select(); sl; sl= sl->next_select()) { List_iterator_fast li(sl->item_list); Item *sel_item; -- cgit v1.2.1 From d0f9e73a43382b8f53b1d23bd3ffdde8e39f3a5e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Sep 2003 13:11:18 +0500 Subject: fix for #1210 include/errmsg.h: Error code added libmysql/errmsg.c: Error message added libmysqld/lib_sql.cc: static inited variable changed to global server_inited libmysqld/libmysqld.c: check for mysql_server_init execution added --- include/errmsg.h | 1 + libmysql/errmsg.c | 9 ++++++--- libmysqld/lib_sql.cc | 7 ++++--- libmysqld/libmysqld.c | 16 ++++++++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/include/errmsg.h b/include/errmsg.h index 1f4e6e12f00..a354c125e36 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -86,3 +86,4 @@ extern const char *client_errors[]; /* Error messages */ #define CR_SHARED_MEMORY_CONNECT_SET_ERROR 2045 #define CR_CONN_UNKNOW_PROTOCOL 2046 #define CR_INVALID_CONN_HANDLE 2047 +#define CR_MYSQL_SERVER_INIT_MISSED 2048 diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index bbb85885886..d27e981aaab 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -71,7 +71,8 @@ const char *client_errors[]= "Can't open shared memory. Server abandoded and don't sent the answer event (%lu)", "Can't open shared memory. Can't send the request event to server (%lu)", "Wrong or unknown protocol", - "Invalid connection handle" + "Invalid connection handle", + "mysql_server_init wasn't called" }; /* Start of code added by Roberto M. Serqueira - martinsc@uol.com.br - 05.24.2001 */ @@ -126,7 +127,8 @@ const char *client_errors[]= "Can't open shared memory. Server abandoded and don't sent the answer event (%lu)", "Can't open shared memory. Can't send the request event to server (%lu)", "Wrong or unknown protocol", - "Invalid connection handle" + "Invalid connection handle", + "mysql_server_init wasn't called" }; #else /* ENGLISH */ @@ -179,7 +181,8 @@ const char *client_errors[]= "Can't open shared memory. Server abandoded and don't sent the answer event (%lu)", "Can't open shared memory. Can't send the request event to server (%lu)", "Wrong or unknown protocol", - "Invalid connection handle" + "Invalid connection handle", + "mysql_server_init wasn't called" }; #endif diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 00ec550273c..31deb1afb01 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -26,7 +26,8 @@ static int fake_argc= 1; static char *fake_argv[]= {(char *)"", 0}; static const char *fake_groups[] = { "server", "embedded", 0 }; -static char inited, org_my_init_done; +static char org_my_init_done; +char server_inited; #if defined (__WIN__) #include "../sql/mysqld.cpp" @@ -181,9 +182,9 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) /* Only call MY_INIT() if it hasn't been called before */ - if (!inited) + if (!server_inited) { - inited=1; + server_inited=1; org_my_init_done=my_init_done; } if (!org_my_init_done) diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 48b3397ee7c..0c772587c4b 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -79,6 +79,8 @@ struct passwd *getpwuid(uid_t); char* getlogin(void); #endif +extern char server_inited; + #ifdef __WIN__ static my_bool is_NT(void) { @@ -210,6 +212,20 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, db ? db : "(Null)", user ? user : "(Null)")); +#ifdef EMBEDDED_LIBRARY + /* + Here we check that mysql_server_init was called before. + Actually we can perform the test for client (not embedded) library as well. + But i'm afraid some old applications will be broken then. + */ + if (!server_inited) + { + mysql->net.last_errno=CR_MYSQL_SERVER_INIT_MISSED; + strmov(mysql->net.last_error,ER(mysql->net.last_errno)); + goto error; + } +#endif /*EMBEDDED_LIBRARY*/ + if (mysql->options.methods_to_use == MYSQL_OPT_USE_REMOTE_CONNECTION) cli_mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag); -- cgit v1.2.1 From 9fd076375bd75b4308917b76faf6674e447c9cf5 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Sep 2003 15:08:53 +0500 Subject: Trimming of embedded library code sql/sql_parse.cc: It's better to check for HAVE_REPLICATION here instead of EMBEDDED_LIBRARY --- sql/sql_parse.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7e520aabf21..d6e0b95af8c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1155,7 +1155,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, mysql_log.write(thd,command,"%s",thd->db); break; } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case COM_REGISTER_SLAVE: { if (!register_slave(thd, (uchar*)packet, packet_length)) @@ -1661,7 +1661,7 @@ mysql_execute_command(THD *thd) } #endif } -#endif /* EMBEDDED_LIBRARY */ +#endif /* !EMBEDDED_LIBRARY */ /* TODO: make derived tables processing 'inside' SELECT processing. TODO: solve problem with depended derived tables in subselects @@ -1837,7 +1837,7 @@ mysql_execute_command(THD *thd) break; } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_SHOW_SLAVE_HOSTS: { if (check_global_access(thd, REPL_SLAVE_ACL)) @@ -1883,7 +1883,7 @@ mysql_execute_command(THD *thd) } -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_CHANGE_MASTER: { if (check_global_access(thd, SUPER_ACL)) @@ -1920,7 +1920,7 @@ mysql_execute_command(THD *thd) else res = load_master_data(thd); break; -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: @@ -1932,7 +1932,7 @@ mysql_execute_command(THD *thd) } #endif -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_LOAD_MASTER_TABLE: { if (!tables->db) @@ -1964,7 +1964,7 @@ mysql_execute_command(THD *thd) UNLOCK_ACTIVE_MI; break; } -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ case SQLCOM_CREATE_TABLE: { @@ -2081,7 +2081,7 @@ mysql_execute_command(THD *thd) res = mysql_create_index(thd, tables, lex->key_list); break; -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SQLCOM_SLAVE_START: { LOCK_ACTIVE_MI; @@ -2114,7 +2114,7 @@ mysql_execute_command(THD *thd) UNLOCK_ACTIVE_MI; break; } -#endif +#endif /* HAVE_REPLICATION */ case SQLCOM_ALTER_TABLE: #if defined(DONT_ALLOW_SHOW_COMMANDS) @@ -4376,7 +4376,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, refresh_status(); if (options & REFRESH_THREADS) flush_thread_cache(); -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION if (options & REFRESH_MASTER) { tmp_write_to_binlog= 0; @@ -4391,7 +4391,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, result=load_des_key_file(des_key_file); } #endif -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION if (options & REFRESH_SLAVE) { tmp_write_to_binlog= 0; -- cgit v1.2.1 From be67ce0b0fcb18a8ef1919e6e1f7557ae2c618f3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Sep 2003 17:00:39 +0500 Subject: fix for #1218 sql/sql_parse.cc: This line fails in libmysqld. And isn't needed while we don't check privileges in embedded library --- sql/sql_parse.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d6e0b95af8c..ff66892262d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2620,8 +2620,10 @@ mysql_execute_command(THD *thd) break; #endif case SQLCOM_SHOW_PROCESSLIST: +#ifndef EMBEDDED_LIBRARY if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) break; +#endif mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS : thd->priv_user,lex->verbose); break; -- cgit v1.2.1 From b036ffec6ca6e5b67aa2ec35481a4b141db11128 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Sep 2003 18:49:23 +0500 Subject: fix for #1219 libmysqld/lib_sql.cc: we need ER() macrodefinition from errmsg.h --- libmysqld/lib_sql.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 31deb1afb01..5b3278694e3 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -37,6 +37,7 @@ char server_inited; C_MODE_START #include +#undef ER #include "errmsg.h" #include @@ -55,12 +56,13 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, { my_bool result= 1; THD *thd=(THD *) mysql->thd; + NET *net= &mysql->net; /* Check that we are calling the client functions in right order */ if (mysql->status != MYSQL_STATUS_READY) { - strmov(thd->net.last_error, - ER(thd->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); + strmov(net->last_error, + ER(net->last_errno=CR_COMMANDS_OUT_OF_SYNC)); return 1; } @@ -76,12 +78,12 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, if (!skip_check) result= thd->net.last_errno ? -1 : 0; - if ((mysql->net.last_errno= thd->net.last_errno)) + if ((net->last_errno= thd->net.last_errno)) { - memcpy(mysql->net.last_error, thd->net.last_error, - sizeof(mysql->net.last_error)); - memcpy(mysql->net.sqlstate, thd->net.sqlstate, - sizeof(mysql->net.sqlstate)); + memcpy(net->last_error, net->last_error, + sizeof(net->last_error)); + memcpy(net->sqlstate, thd->net.sqlstate, + sizeof(net->sqlstate)); } mysql->warning_count= ((THD*)mysql->thd)->total_warn_count; return result; -- cgit v1.2.1 From b2a6994b22bff1ee9cb9afd730bd0b88eff978ba Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Sep 2003 15:23:38 +0300 Subject: Fix for a bug #1226. Happens when braces are used on a single select, which leads to the uninitialized global parameters structure. --- mysql-test/r/subselect.result | 6 ++++++ mysql-test/t/subselect.test | 2 ++ sql/sql_yacc.yy | 5 +++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 625fb9f9c29..52cd500944c 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1368,4 +1368,10 @@ insert into t1 values ('tttt'); select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); s1 tttt +explain (select * from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +(select * from t1); +s1 +tttt drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 4b8d63b681e..bd6a4037f3d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -931,4 +931,6 @@ create table t1 (s1 char(5)); select (select 'a','b' from t1 union select 'a','b' from t1) from t1; insert into t1 values ('tttt'); select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); +explain (select * from t1); +(select * from t1); drop table t1; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c753123b2be..b84a21b1440 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2012,8 +2012,9 @@ select_init: YYABORT; } /* select in braces, can't contain global parameters */ - sel->master_unit()->global_parameters= - sel->master_unit()->fake_select_lex; + if (sel->master_unit()->fake_select_lex) + sel->master_unit()->global_parameters= + sel->master_unit()->fake_select_lex; } union_opt; select_init2: -- cgit v1.2.1