diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 3230f3c119f..eaf79d29cee 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -87,6 +87,7 @@ hf@deer.mysql.r18.ru hf@genie.(none) holyfoot@mysql.com igor@hundin.mysql.fi +igor@igor-inspiron.creware.com igor@linux.local igor@rurik.mysql.com ingo@mysql.com @@ -236,6 +237,7 @@ rburnett@bk-internal.mysql.com rburnett@build.mysql.com reggie@bob.(none) reggie@mdk10.(none) +reggie@monster. root@home.(none) root@mc04.(none) root@x3.internalnet diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp index 466884f3cd9..84ffb9b5829 100644 --- a/extra/yassl/src/ssl.cpp +++ b/extra/yassl/src/ssl.cpp @@ -36,7 +36,7 @@ #include "handshake.hpp" #include "yassl_int.hpp" #include - +#include "runtime.hpp" namespace yaSSL { diff --git a/include/mysql.h b/include/mysql.h index b2b2e239758..84284fa0661 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -74,14 +74,14 @@ extern char *mysql_unix_port; #define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG) #define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG) #define IS_BLOB(n) ((n) & BLOB_FLAG) -#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR) +#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR || (t) == FIELD_TYPE_NEWDECIMAL) #define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG) #define INTERNAL_NUM_FIELD(f) (((f)->type <= FIELD_TYPE_INT24 && ((f)->type != FIELD_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == FIELD_TYPE_YEAR) typedef struct st_mysql_field { char *name; /* Name of column */ - char *org_name; /* Original column name, if an alias */ + char *org_name; /* Original column name, if an alias */ char *table; /* Table of column if column was a field */ char *org_table; /* Org table name, if table was an alias */ char *db; /* Database for table */ diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 5fb21004469..a854cf4c7b0 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -160,3 +160,20 @@ t1 CREATE TABLE `t1` ( `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE t1 (EMPNUM INT); +INSERT INTO t1 VALUES (0), (2); +CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); +INSERT INTO t2 VALUES (0.0), (9.0); +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, +t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 +FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; +CEMPNUM EMPMUM1 EMPNUM2 +0.00 0 0.00 +2.00 2 NULL +SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, +t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 +FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; +CEMPNUM EMPMUM1 EMPNUM2 +0.00 0 0.00 +2.00 2 NULL +DROP TABLE t1,t2; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index fed3ff07a13..f2cfce9085d 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -110,3 +110,22 @@ explain extended SELECT COALESCE('a' COLLATE latin1_bin,'b'); SHOW CREATE TABLE t1; DROP TABLE t1; + +# +# Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL +# + +CREATE TABLE t1 (EMPNUM INT); +INSERT INTO t1 VALUES (0), (2); +CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); +INSERT INTO t2 VALUES (0.0), (9.0); + +SELECT COALESCE(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, + t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 + FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; + +SELECT IFNULL(t2.EMPNUM,t1.EMPNUM) AS CEMPNUM, + t1.EMPNUM AS EMPMUM1, t2.EMPNUM AS EMPNUM2 + FROM t1 LEFT JOIN t2 ON t1.EMPNUM=t2.EMPNUM; + +DROP TABLE t1,t2; diff --git a/mysys/my_access.c b/mysys/my_access.c index 28210bdfc7d..89e90e16f18 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -44,7 +44,7 @@ int my_access(const char *path, int amode) result= GetFileAttributesEx(path, GetFileExInfoStandard, &fileinfo); if (! result || - (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && (amode & W_OK)) + (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) && (amode & F_OK)) { my_errno= errno= EACCES; return -1; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1703a405035..d956e692152 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -5963,11 +5963,14 @@ ha_innobase::external_lock( TABLES if AUTOCOMMIT=1. It does not make much sense to acquire an InnoDB table lock if it is released immediately at the end of LOCK TABLES, and InnoDB's table locks in that case cause - VERY easily deadlocks. */ + VERY easily deadlocks. We do not set InnoDB table locks when + MySQL sets them at the start of a stored procedure call + (MySQL does have thd->in_lock_tables TRUE there). */ if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && + thd->lex->sql_command != SQLCOM_CALL && thd->variables.innodb_table_locks && (thd->options & OPTION_NOT_AUTOCOMMIT)) { @@ -6478,11 +6481,21 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { + /* Starting from 5.0.7, we weaken also the table locks + set at the start of a MySQL stored procedure call, just like + we weaken the locks set at the start of an SQL statement. + MySQL does set thd->in_lock_tables TRUE there, but in reality + we do not need table locks to make the execution of a + single transaction stored procedure call deterministic + (if it does not use a consistent read). */ + /* If we are not doing a LOCK TABLE or DISCARD/IMPORT TABLESPACE or TRUNCATE TABLE, then allow multiple writers */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !thd->in_lock_tables + lock_type <= TL_WRITE) + && (!thd->in_lock_tables + || thd->lex->sql_command == SQLCOM_CALL) && !thd->tablespace_op && thd->lex->sql_command != SQLCOM_TRUNCATE && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { @@ -6496,7 +6509,10 @@ ha_innobase::store_lock( to t2. Convert the lock to a normal read lock to allow concurrent inserts to t2. */ - if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) { + if (lock_type == TL_READ_NO_INSERT + && (!thd->in_lock_tables + || thd->lex->sql_command == SQLCOM_CALL)) { + lock_type = TL_READ; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index eb0dddd3e28..3f25d473792 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1116,8 +1116,8 @@ Item_func_ifnull::fix_length_and_dec() max_length= (max(args[0]->max_length - args[0]->decimals, args[1]->max_length - args[1]->decimals) + decimals); - agg_result_type(&cached_result_type, args, 2); - switch (cached_result_type) { + agg_result_type(&hybrid_type, args, 2); + switch (hybrid_type) { case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); break; @@ -1155,7 +1155,7 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table) } double -Item_func_ifnull::val_real() +Item_func_ifnull::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); @@ -1171,7 +1171,7 @@ Item_func_ifnull::val_real() } longlong -Item_func_ifnull::val_int() +Item_func_ifnull::int_op() { DBUG_ASSERT(fixed == 1); longlong value=args[0]->val_int(); @@ -1187,7 +1187,7 @@ Item_func_ifnull::val_int() } -my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) +my_decimal *Item_func_ifnull::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); my_decimal *value= args[0]->val_decimal(decimal_value); @@ -1204,7 +1204,7 @@ my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) String * -Item_func_ifnull::val_str(String *str) +Item_func_ifnull::str_op(String *str) { DBUG_ASSERT(fixed == 1); String *res =args[0]->val_str(str); @@ -1685,7 +1685,7 @@ void Item_func_case::print(String *str) Coalesce - return first not NULL argument. */ -String *Item_func_coalesce::val_str(String *str) +String *Item_func_coalesce::str_op(String *str) { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1699,7 +1699,7 @@ String *Item_func_coalesce::val_str(String *str) return 0; } -longlong Item_func_coalesce::val_int() +longlong Item_func_coalesce::int_op() { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1713,7 +1713,7 @@ longlong Item_func_coalesce::val_int() return 0; } -double Item_func_coalesce::val_real() +double Item_func_coalesce::real_op() { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1728,7 +1728,7 @@ double Item_func_coalesce::val_real() } -my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) +my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); null_value= 0; @@ -1745,8 +1745,8 @@ my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) void Item_func_coalesce::fix_length_and_dec() { - agg_result_type(&cached_result_type, args, arg_count); - switch (cached_result_type) { + agg_result_type(&hybrid_type, args, arg_count); + switch (hybrid_type) { case STRING_RESULT: count_only_length(); decimals= NOT_FIXED_DEC; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a929d509723..7a22e76b217 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -453,23 +453,19 @@ public: }; -class Item_func_coalesce :public Item_func +class Item_func_coalesce :public Item_func_numhybrid { protected: - enum Item_result cached_result_type; - Item_func_coalesce(Item *a, Item *b) - :Item_func(a, b), cached_result_type(INT_RESULT) - {} + Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {} public: - Item_func_coalesce(List &list) - :Item_func(list),cached_result_type(INT_RESULT) - {} - double val_real(); - longlong val_int(); - String *val_str(String *); - my_decimal *val_decimal(my_decimal *); + Item_func_coalesce(List &list) :Item_func_numhybrid(list) {} + double real_op(); + longlong int_op(); + String *str_op(String *); + my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); - enum Item_result result_type () const { return cached_result_type; } + void find_num_type() {} + enum Item_result result_type () const { return hybrid_type; } const char *func_name() const { return "coalesce"; } table_map not_null_tables() const { return 0; } }; @@ -482,10 +478,10 @@ protected: bool field_type_defined; public: Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {} - double val_real(); - longlong val_int(); - String *val_str(String *str); - my_decimal *val_decimal(my_decimal *); + double real_op(); + longlong int_op(); + String *str_op(String *str); + my_decimal *decimal_op(my_decimal *); enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 92c51553644..18c2efb0ace 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -817,6 +817,8 @@ String *Item_func_numhybrid::val_str(String *str) str->set(nr,decimals,&my_charset_bin); break; } + case STRING_RESULT: + return str_op(&str_value); default: DBUG_ASSERT(0); } @@ -841,6 +843,14 @@ double Item_func_numhybrid::val_real() return (double)int_op(); case REAL_RESULT: return real_op(); + case STRING_RESULT: + { + char *end_not_used; + int err_not_used; + String *res= str_op(&str_value); + return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), + &end_not_used, &err_not_used) : 0.0); + } default: DBUG_ASSERT(0); } @@ -865,6 +875,15 @@ longlong Item_func_numhybrid::val_int() return int_op(); case REAL_RESULT: return (longlong)real_op(); + case STRING_RESULT: + { + char *end_not_used; + int err_not_used; + String *res= str_op(&str_value); + CHARSET_INFO *cs= str_value.charset(); + return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end_not_used, + &err_not_used) : 0); + } default: DBUG_ASSERT(0); } @@ -893,6 +912,12 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) break; } case STRING_RESULT: + { + String *res= str_op(&str_value); + str2my_decimal(E_DEC_FATAL_ERROR, (char*) res->ptr(), + res->length(), res->charset(), decimal_value); + break; + } case ROW_RESULT: default: DBUG_ASSERT(0); @@ -2325,9 +2350,6 @@ longlong Item_func_field::val_int() { DBUG_ASSERT(fixed == 1); - if (args[0]->is_null()) - return 0; - if (cmp_type == STRING_RESULT) { String *field; @@ -2343,6 +2365,8 @@ longlong Item_func_field::val_int() else if (cmp_type == INT_RESULT) { longlong val= args[0]->val_int(); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count ; i++) { if (!args[i]->is_null() && val == args[i]->val_int()) @@ -2353,6 +2377,8 @@ longlong Item_func_field::val_int() { my_decimal dec_arg_buf, *dec_arg, dec_buf, *dec= args[0]->val_decimal(&dec_buf); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count; i++) { dec_arg= args[i]->val_decimal(&dec_arg_buf); @@ -2363,6 +2389,8 @@ longlong Item_func_field::val_int() else { double val= args[0]->val_real(); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count ; i++) { if (!args[i]->is_null() && val == args[i]->val_real()) diff --git a/sql/item_func.h b/sql/item_func.h index b53f2a0b9c6..f0c7e25ad53 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -189,10 +189,13 @@ class Item_func_numhybrid: public Item_func protected: Item_result hybrid_type; public: - Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) + Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(Item *a,Item *b) - :Item_func(a,b),hybrid_type(REAL_RESULT) + :Item_func(a,b), hybrid_type(REAL_RESULT) + {} + Item_func_numhybrid(List &list) + :Item_func(list), hybrid_type(REAL_RESULT) {} enum Item_result result_type () const { return hybrid_type; } @@ -208,6 +211,7 @@ public: virtual longlong int_op()= 0; virtual double real_op()= 0; virtual my_decimal *decimal_op(my_decimal *)= 0; + virtual String *str_op(String *)= 0; bool is_null() { (void) val_real(); return null_value; } }; @@ -220,6 +224,7 @@ public: void fix_num_length_and_dec(); void find_num_type(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } }; @@ -231,6 +236,7 @@ class Item_num_op :public Item_func_numhybrid virtual void result_precision()= 0; void print(String *str) { print_op(str); } void find_num_type(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } }; diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 2fd603d9381..958268fc314 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -28,7 +28,7 @@ template class Bitmap uchar buffer[(default_width+7)/8]; public: Bitmap() { init(); } - Bitmap(Bitmap& from) { *this=from; } + Bitmap(const Bitmap& from) { *this=from; } explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); } void init() { bitmap_init(&map, buffer, default_width, 0); } void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); } @@ -61,18 +61,17 @@ public: my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } char *print(char *buf) const { - char *s=buf; int i; - for (i=sizeof(buffer)-1; i>=0 ; i--) + char *s=buf; + const uchar *e=buffer, *b=e+sizeof(buffer)-1; + while (!*b && b>e) + b--; + if ((*s=_dig_vec_upper[*b >> 4]) != '0') + s++; + *s++=_dig_vec_upper[*b & 15]; + while (--b>=e) { - if ((*s=_dig_vec_upper[buffer[i] >> 4]) != '0') - break; - if ((*s=_dig_vec_upper[buffer[i] & 15]) != '0') - break; - } - for (s++, i-- ; i>=0 ; i--) - { - *s++=_dig_vec_upper[buffer[i] >> 4]; - *s++=_dig_vec_upper[buffer[i] & 15]; + *s++=_dig_vec_upper[*b >> 4]; + *s++=_dig_vec_upper[*b & 15]; } *s=0; return buf; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 429ffb90ba8..27ef3fcea6f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5799,6 +5799,7 @@ make_join_readinfo(JOIN *join, uint options) if (!table->no_keyread) { if (tab->select && tab->select->quick && + tab->select->quick->index != MAX_KEY && //not index_merge table->used_keys.is_set(tab->select->quick->index)) { table->key_read=1; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9a8ee44c54c..002076afd90 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7455,12 +7455,16 @@ static void test_explain_bug() verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN, 0); - verify_prepare_field(result, 6, "key_len", "", - (mysql_get_server_version(mysql) <= 50000 ? - MYSQL_TYPE_LONGLONG : MYSQL_TYPE_VAR_STRING), - "", "", "", - (mysql_get_server_version(mysql) <= 50000 ? 3 : 4096), - 0); + if (mysql_get_server_version(mysql) <= 50000) + { + verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_LONGLONG, "", + "", "", 3, 0); + } + else + { + verify_prepare_field(result, 6, "key_len", "", MYSQL_TYPE_VAR_STRING, "", + "", "", NAME_LEN*MAX_KEY, 0); + } verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*16, 0);