diff options
54 files changed, 617 insertions, 281 deletions
diff --git a/.bzrignore b/.bzrignore index f27193d0adf..608a414ae20 100644 --- a/.bzrignore +++ b/.bzrignore @@ -754,6 +754,7 @@ ndb/examples/ndbapi_example3/ndbapi_example3 ndb/examples/ndbapi_example5/ndbapi_example5 ndb/examples/select_all/select_all ndb/include/ndb_global.h +ndb/include/ndb_types.h ndb/include/ndb_version.h ndb/lib/libMGM_API.so ndb/lib/libNDB_API.so diff --git a/BUILD/compile-solaris-sparc-purify b/BUILD/compile-solaris-sparc-purify index 71a60e45cb0..c895d99c2cf 100755 --- a/BUILD/compile-solaris-sparc-purify +++ b/BUILD/compile-solaris-sparc-purify @@ -3,28 +3,27 @@ while test $# -gt 0 do case "$1" in - --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;; - -h | --help ) cat <<EOF; exit 0 ;; -Usage: $0 [-h|-n] [configure-options] - --debug Compile with DBUG enabled -EOF - *) echo "No such option '$1'" ; exit ;; + --debug) EXTRA_CONFIG_FLAGS=--with-debug; shift ;; + -h | --help ) + echo "Usage: $0 [-h|-n] [configure-options]" + echo " --debug Compile with DBUG enabled" + exit 0 ;; + *) echo "No such option '$1'" ; exit ;; esac done gmake -k clean || true /bin/rm -f */.deps/*.P config.cache aclocal && autoheader && aclocal && automake && autoconf -(cd bdb/dist && sh s_all) +# (cd bdb/dist && sh s_all) (cd innobase && aclocal && autoheader && aclocal && automake && autoconf) -CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-berkeley-db --with-innodb $EXTRA_CONFIG_FLAGS +CFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wimplicit-int -Wparentheses -Wsign-compare -Wwrite-strings -Wunused -DHAVE_purify -DEXTRA_DEBUG -O2" CXX=gcc CXXLD=g++ CXXFLAGS="-g -Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wchar-subscripts -Wformat -Wparentheses -Wsign-compare -Wwrite-strings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor -felide-constructors -fno-exceptions -fno-rtti -DHAVE_purify -DEXTRA_DEBUG -O2" ./configure --prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --without-berkeley-db --with-embedded-server --with-innodb $EXTRA_CONFIG_FLAGS gmake -j 4 cd sql ; mv mysqld mysqld-org ; -make CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify -make CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify -make CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov +gmake CXXLD="purify -best-effort g++" mysqld ; mv mysqld mysqld-purify +gmake CXXLD="quantify -best-effort g++" mysqld ; mv mysqld mysqld-quantify +gmake CXXLD="purecov -best-effort g++" mysqld ; mv mysqld mysqld-purecov mv mysqld-org mysqld - diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index c640a1c1bb7..68d5b5166ea 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -265,7 +265,8 @@ if ($opt_stage <= 1) $opt_config_options.= " --with-berkeley-db" if ($opt_bdb); $opt_config_options.= " --with-zlib-dir=bundled" if ($opt_bundled_zlib); $opt_config_options.= " --with-client-ldflags=-all-static" if ($opt_static_client); - $opt_config_options.= " --with-debug" if ($opt_with_debug); + $opt_config_options.= " --with-debug" if ($opt_with_debug); + $opt_config_options.= " --without-ndb-debug" if ($opt_with_debug && $opt_with_cluster); $opt_config_options.= " --with-libwrap" if ($opt_libwrap); $opt_config_options.= " --with-low-memory" if ($opt_with_low_memory); $opt_config_options.= " --with-mysqld-ldflags=-all-static" if ($opt_static_server); diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index e62ec8d7cea..3bef8fb0452 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -833,7 +833,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) if (argv[1][0]) { char *pw= argv[1]; - bool old= find_type(argv[0], &command_typelib, 2) == ADMIN_OLD_PASSWORD; + bool old= (find_type(argv[0], &command_typelib, 2) == + ADMIN_OLD_PASSWORD); #ifdef __WIN__ uint pw_len= strlen(pw); if (pw_len > 1 && pw[0] == '\'' && pw[pw_len-1] == '\'') @@ -844,21 +845,29 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) If we don't already know to use an old-style password, see what the server is using */ - if (!old) { - if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'")) { + if (!old) + { + if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'")) + { my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'", MYF(ME_BELL),mysql_error(mysql)); return -1; - } else { + } + else + { MYSQL_RES *res= mysql_store_result(mysql); - if (!res) { - my_printf_error(0, "Could not get old_passwords setting from server; error: '%s'", + if (!res) + { + my_printf_error(0, + "Could not get old_passwords setting from " + "server; error: '%s'", MYF(ME_BELL),mysql_error(mysql)); return -1; } - if (!mysql_num_rows(res)) { + if (!mysql_num_rows(res)) old= 1; - } else { + else + { MYSQL_ROW row= mysql_fetch_row(res); old= !strncmp(row[1], "ON", 2); } diff --git a/heap/hp_create.c b/heap/hp_create.c index 0580c178498..17aa92c9201 100644 --- a/heap/hp_create.c +++ b/heap/hp_create.c @@ -154,15 +154,15 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, keyseg->flag= 0; keyseg->null_bit= 0; keyseg++; - - init_tree(&keyinfo->rb_tree, 0, 0, sizeof(byte*), + + init_tree(&keyinfo->rb_tree, 0, 0, sizeof(byte*), (qsort_cmp2)keys_compare, 1, NULL, NULL); keyinfo->delete_key= hp_rb_delete_key; keyinfo->write_key= hp_rb_write_key; } else { - init_block(&keyinfo->block, sizeof(HASH_INFO), min_records, + init_block(&keyinfo->block, sizeof(HASH_INFO), min_records, max_records); keyinfo->delete_key= hp_delete_key; keyinfo->write_key= hp_write_key; @@ -171,6 +171,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, } share->min_records= min_records; share->max_records= max_records; + share->max_table_size= create_info->max_table_size; share->data_length= share->index_length= 0; share->reclength= reclength; share->blength= 1; diff --git a/heap/hp_write.c b/heap/hp_write.c index 171998e9125..a60d32eecb6 100644 --- a/heap/hp_write.c +++ b/heap/hp_write.c @@ -143,7 +143,8 @@ static byte *next_free_record_pos(HP_SHARE *info) } if (!(block_pos=(info->records % info->block.records_in_block))) { - if (info->records > info->max_records && info->max_records) + if ((info->records > info->max_records && info->max_records) || + (info->data_length + info->index_length >= info->max_table_size)) { my_errno=HA_ERR_RECORD_FILE_FULL; DBUG_RETURN(NULL); diff --git a/include/heap.h b/include/heap.h index 5e83a6e2cb5..ac2b38d1f2d 100644 --- a/include/heap.h +++ b/include/heap.h @@ -125,8 +125,8 @@ typedef struct st_hp_keydef /* Key definition with open */ TREE rb_tree; int (*write_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, const byte *record, byte *recpos); - int (*delete_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, - const byte *record, byte *recpos, int flag); + int (*delete_key)(struct st_heap_info *info, struct st_hp_keydef *keyinfo, + const byte *record, byte *recpos, int flag); uint (*get_key_length)(struct st_hp_keydef *keydef, const byte *key); } HP_KEYDEF; @@ -135,7 +135,7 @@ typedef struct st_heap_share HP_BLOCK block; HP_KEYDEF *keydef; ulong min_records,max_records; /* Params to open */ - ulong data_length,index_length; + ulong data_length,index_length,max_table_size; uint records; /* records */ uint blength; /* records rounded up to 2^n */ uint deleted; /* Deleted records in database */ @@ -185,6 +185,7 @@ typedef struct st_heap_create_info { uint auto_key; uint auto_key_type; + ulong max_table_size; ulonglong auto_increment; } HP_CREATE_INFO; diff --git a/include/m_string.h b/include/m_string.h index 97d34421537..d3465363beb 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -215,7 +215,7 @@ extern char *strstr(const char *, const char *); extern int is_prefix(const char *, const char *); /* Conversion routines */ -double my_strtod(const char *str, char **end); +double my_strtod(const char *str, char **end, int *error); double my_atof(const char *nptr); extern char *llstr(longlong value,char *buff); diff --git a/include/my_sys.h b/include/my_sys.h index 5b0390c7d72..d11dc4a3e46 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -688,6 +688,7 @@ extern int init_io_cache(IO_CACHE *info,File file,uint cachesize, extern my_bool reinit_io_cache(IO_CACHE *info,enum cache_type type, my_off_t seek_offset,pbool use_async_io, pbool clear_cache); +extern void setup_io_cache(IO_CACHE* info); extern int _my_b_read(IO_CACHE *info,byte *Buffer,uint Count); #ifdef THREAD extern int _my_b_read_r(IO_CACHE *info,byte *Buffer,uint Count); diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index 9b8fb084e33..00048bf6fbb 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -166,6 +166,17 @@ dtype_is_non_binary_string_type( } /************************************************************************* +Gets the MySQL charset-collation code for MySQL string types. */ + +ulint +dtype_get_charset_coll_noninline( +/*=============================*/ + ulint prtype) /* in: precise data type */ +{ + return(dtype_get_charset_coll(prtype)); +} + +/************************************************************************* Forms a precise type from the < 4.1.2 format precise type plus the charset-collation code. */ diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index c263d2bf613..02c874836fd 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -234,6 +234,13 @@ dtype_get_prtype( dtype_t* type); /************************************************************************* Gets the MySQL charset-collation code for MySQL string types. */ + +ulint +dtype_get_charset_coll_noninline( +/*=============================*/ + ulint prtype);/* in: precise data type */ +/************************************************************************* +Gets the MySQL charset-collation code for MySQL string types. */ UNIV_INLINE ulint dtype_get_charset_coll( diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 3a4c255911d..2ef260829fc 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -456,6 +456,8 @@ struct mysql_row_templ_struct { zero if column cannot be NULL */ ulint type; /* column type in Innobase mtype numbers DATA_CHAR... */ + ulint charset; /* MySQL charset-collation code + of the column, or zero */ ulint is_unsigned; /* if a column type is an integer type and this field is != 0, then it is an unsigned integer type */ diff --git a/innobase/include/row0mysql.ic b/innobase/include/row0mysql.ic index 4ecd66e06ec..fc922b52d0a 100644 --- a/innobase/include/row0mysql.ic +++ b/innobase/include/row0mysql.ic @@ -91,12 +91,33 @@ row_mysql_store_col_in_innobase_format( } } else if (type == DATA_VARCHAR || type == DATA_VARMYSQL || type == DATA_BINARY) { + /* Remove trailing spaces. */ + + /* Handle UCS2 strings differently. As no new + collations will be introduced in 4.1, we hardcode the + charset-collation codes here. In 5.0, the logic will + be based on mbminlen. */ + ulint cset = dtype_get_charset_coll( + dtype_get_prtype(dfield_get_type(dfield))); ptr = row_mysql_read_var_ref(&col_len, mysql_data); - - /* Remove trailing spaces */ - while (col_len > 0 && ptr[col_len - 1] == ' ') { - col_len--; - } + if (cset == 35/*ucs2_general_ci*/ + || cset == 90/*ucs2_bin*/ + || (cset >= 128/*ucs2_unicode_ci*/ + && cset <= 144/*ucs2_persian_ci*/)) { + /* space=0x0020 */ + /* Trim "half-chars", just in case. */ + col_len &= ~1; + + while (col_len >= 2 && ptr[col_len - 2] == 0x00 + && ptr[col_len - 1] == 0x20) { + col_len -= 2; + } + } else { + /* space=0x20 */ + while (col_len > 0 && ptr[col_len - 1] == 0x20) { + col_len--; + } + } } else if (type == DATA_BLOB) { ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len); } diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index 75af1a212b4..8df0f97c4ff 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -75,6 +75,10 @@ extern dulint srv_start_lsn; void set_panic_flag_for_netware(void); #endif +#ifdef HAVE_DARWIN_THREADS +extern ibool srv_have_fullfsync; +#endif + extern ulint srv_sizeof_trx_t_in_ha_innodb_cc; extern ibool srv_is_being_started; diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index a30d14f07bb..64d80350275 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -1773,19 +1773,31 @@ os_file_flush( #else int ret; -#if defined(HAVE_DARWIN_THREADS) && defined(F_FULLFSYNC) +#if defined(HAVE_DARWIN_THREADS) +# ifndef F_FULLFSYNC + /* The following definition is from the Mac OS X 10.3 <sys/fcntl.h> */ +# define F_FULLFSYNC 51 /* fsync + ask the drive to flush to the media */ +# elif F_FULLFSYNC != 51 +# error "F_FULLFSYNC != 51: ABI incompatibility with Mac OS X 10.3" +# endif /* Apple has disabled fsync() for internal disk drives in OS X. That caused corruption for a user when he tested a power outage. Let us in OS X use a nonstandard flush method recommended by an Apple engineer. */ - ret = fcntl(file, F_FULLFSYNC, NULL); - - if (ret) { - /* If we are not on a file system that supports this, then - fall back to a plain fsync. */ + if (!srv_have_fullfsync) { + /* If we are not on an operating system that supports this, + then fall back to a plain fsync. */ ret = fsync(file); + } else { + ret = fcntl(file, F_FULLFSYNC, NULL); + + if (ret) { + /* If we are not on a file system that supports this, + then fall back to a plain fsync. */ + ret = fsync(file); + } } #elif HAVE_FDATASYNC ret = fdatasync(file); diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c index 6473d356ba8..193bda75f24 100644 --- a/innobase/rem/rem0cmp.c +++ b/innobase/rem/rem0cmp.c @@ -262,22 +262,6 @@ cmp_whole_field( "InnoDB: comparison!\n"); } - /* MySQL does not pad the ends of strings with spaces in a - comparison. That would cause a foreign key check to fail for - non-latin1 character sets if we have different length columns. - To prevent that we remove trailing spaces here before doing - the comparison. NOTE that if we in the future map more MySQL - types to DATA_MYSQL or DATA_VARMYSQL, we have to change this - code. */ - - while (a_length > 0 && a[a_length - 1] == ' ') { - a_length--; - } - - while (b_length > 0 && b[b_length - 1] == ' ') { - b_length--; - } - return(innobase_mysql_cmp( (int)(type->prtype & DATA_MYSQL_TYPE_MASK), (uint)dtype_get_charset_coll(type->prtype), diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index f3a5f911171..8512e796a72 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2271,9 +2271,6 @@ row_sel_field_store_in_mysql_format( dest = row_mysql_store_var_len(dest, len); ut_memcpy(dest, data, len); - /* Pad with trailing spaces */ - memset(dest + len, ' ', col_len - len); - /* ut_ad(col_len >= len + 2); No real var implemented in MySQL yet! */ @@ -2406,7 +2403,45 @@ row_sel_store_mysql_rec( mysql_rec + templ->mysql_col_offset, templ->mysql_col_len, data, len, templ->type, templ->is_unsigned); - + + if (templ->type == DATA_VARCHAR + || templ->type == DATA_VARMYSQL + || templ->type == DATA_BINARY) { + /* Pad with trailing spaces */ + data = mysql_rec + templ->mysql_col_offset; + + /* Handle UCS2 strings differently. As no new + collations will be introduced in 4.1, we + hardcode the charset-collation codes here. + 5.0 will use a different approach. */ + if (templ->charset == 35 + || templ->charset == 90 + || (templ->charset >= 128 + && templ->charset <= 144)) { + /* space=0x0020 */ + ulint col_len = templ->mysql_col_len; + + ut_a(!(col_len & 1)); + if (len & 1) { + /* A 0x20 has been stripped + from the column. + Pad it back. */ + goto pad_0x20; + } + /* Pad the rest of the string + with 0x0020 */ + while (len < col_len) { + data[len++] = 0x00; + pad_0x20: + data[len++] = 0x20; + } + } else { + /* space=0x20 */ + memset(data + len, 0x20, + templ->mysql_col_len - len); + } + } + /* Cleanup */ if (extern_field_heap) { mem_heap_free(extern_field_heap); @@ -2442,8 +2477,29 @@ row_sel_store_mysql_rec( pad_char = '\0'; } - memset(mysql_rec + templ->mysql_col_offset, pad_char, - templ->mysql_col_len); + /* Handle UCS2 strings differently. As no new + collations will be introduced in 4.1, + we hardcode the charset-collation codes here. + 5.0 will use a different approach. */ + if (templ->charset == 35 + || templ->charset == 90 + || (templ->charset >= 128 + && templ->charset <= 144)) { + /* There are two bytes per char, so the length + has to be an even number. */ + ut_a(!(templ->mysql_col_len & 1)); + data = mysql_rec + templ->mysql_col_offset; + len = templ->mysql_col_len; + /* Pad with 0x0020. */ + while (len >= 2) { + *data++ = 0x00; + *data++ = 0x20; + len -= 2; + } + } else { + memset(mysql_rec + templ->mysql_col_offset, + pad_char, templ->mysql_col_len); + } } } diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 061bdb82d3e..983a8306773 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -61,6 +61,11 @@ dulint srv_start_lsn; /* Log sequence number at shutdown */ dulint srv_shutdown_lsn; +#ifdef HAVE_DARWIN_THREADS +# include <sys/utsname.h> +ibool srv_have_fullfsync = FALSE; +#endif + ibool srv_start_raw_disk_in_use = FALSE; static ibool srv_start_has_been_called = FALSE; @@ -935,6 +940,28 @@ innobase_start_or_create_for_mysql(void) ulint i; ibool srv_file_per_table_original_value = srv_file_per_table; mtr_t mtr; +#ifdef HAVE_DARWIN_THREADS +# ifdef F_FULLFSYNC + /* This executable has been compiled on Mac OS X 10.3 or later. + Assume that F_FULLFSYNC is available at run-time. */ + srv_have_fullfsync = TRUE; +# else /* F_FULLFSYNC */ + /* This executable has been compiled on Mac OS X 10.2 + or earlier. Determine if the executable is running + on Mac OS X 10.3 or later. */ + struct utsname utsname; + if (uname(&utsname)) { + fputs("InnoDB: cannot determine Mac OS X version!\n", stderr); + } else { + srv_have_fullfsync = strcmp(utsname.release, "7.") >= 0; + } + if (!srv_have_fullfsync) { + fputs( +"InnoDB: On Mac OS X, fsync() may be broken on internal drives,\n" +"InnoDB: making transactions unsafe!\n", stderr); + } +# endif /* F_FULLFSYNC */ +#endif /* HAVE_DARWIN_THREADS */ if (sizeof(ulint) != sizeof(void*)) { fprintf(stderr, diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 6c455e131bf..ec794373baf 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -427,6 +427,9 @@ while test $# -gt 0; do --fast) FAST_START=1 ;; + --use-old-data) + USE_OLD_DATA=1; + ;; -- ) shift; break ;; --* ) $ECHO "Unrecognized option: $1"; exit 1 ;; * ) break ;; @@ -773,12 +776,14 @@ report_stats () { mysql_install_db () { $ECHO "Removing Stale Files" - $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1" $SLAVE_MYDDIR $MY_LOG_DIR/* - $ECHO "Installing Master Databases" - $INSTALL_DB - if [ $? != 0 ]; then + if [ -z "$USE_OLD_DATA" ]; then + $RM -rf $MASTER_MYDDIR $MASTER_MYDDIR"1" + $ECHO "Installing Master Databases" + $INSTALL_DB + if [ $? != 0 ]; then error "Could not install master test DBs" - exit 1 + exit 1 + fi fi if [ ! -z "$USE_NDBCLUSTER" ] then @@ -790,6 +795,7 @@ mysql_install_db () { fi fi $ECHO "Installing Slave Databases" + $RM -rf $SLAVE_MYDDIR $MY_LOG_DIR/* $INSTALL_DB -slave if [ $? != 0 ]; then error "Could not install slave test DBs" diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index dfaf5758699..272f6f592b1 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -464,3 +464,8 @@ group_concat(a) ABW ABW drop table t1; +CREATE TABLE t1 (id int); +SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; +gc +NULL +DROP TABLE t1; diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index f80b0281dd8..6556d2be6ad 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -107,13 +107,16 @@ timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") 46:58:57.999999 select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") --23:59:59.999999 +-24:00:00.000001 select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); timediff("1997-12-31 23:59:59.000001","23:59:59.000001") NULL select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") -00:00:00.000001 +select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50"); +timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50") +-00:00:00.000001 select maketime(10,11,12); maketime(10,11,12) 10:11:12 @@ -185,7 +188,7 @@ f8 date YES NULL f9 time YES NULL select * from t1; f1 f2 f3 f4 f5 f6 f7 f8 f9 -1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -23:59:59 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59 +1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -24:00:00 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59 create table test(t1 datetime, t2 time, t3 time, t4 datetime); insert into test values ('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 6df5f633b88..64cdb76ead8 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -295,7 +295,6 @@ execute stmt4; prepare stmt4 from ' show full processlist '; execute stmt4; Id User Host db Command Time State Info -number root localhost test Query time NULL show full processlist prepare stmt4 from ' show grants for user '; prepare stmt4 from ' show create table t2 '; ERROR HY000: This command is not supported in the prepared statement protocol yet diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index fb228d37da3..f28317ce947 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -768,7 +768,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308); INSERT INTO t1 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308'); INSERT INTO t1 (col1) VALUES (-2.2E-330); INSERT INTO t1 (col1) VALUES (+1.7E+309); -ERROR 22007: Illegal double '1.7E+309' value found during parsing +Got one of the listed errors INSERT INTO t1 (col2) VALUES (-1.1E-3); ERROR 22003: Out of range value adjusted for column 'col2' at row 1 INSERT INTO t1 (col1) VALUES ('+1.8E+309'); diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 449d9b0ea4b..cc42c506abe 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1,t2; SELECT 10,10.0,10.,.1e+2,100.0e-1; 10 10.0 10. .1e+2 100.0e-1 10 10.0 10 10 10 @@ -8,6 +8,9 @@ SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1; 1e1 1.e1 1.0e1 1e+1 1.e+1 1.0e+1 1e-1 1.e-1 1.0e-1 10 10 10 10 10 10 0.1 0.1 0.1 +SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01; +0.001e+1 0.001e-1 -0.001e+01 -0.001e-01 +0.01 0.0001 -0.01 -0.0001 create table t1 (f1 float(24),f2 float(52)); show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 61c167c6264..1e0b5deaf25 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -426,3 +426,13 @@ max(t) 2004-01-01 01:00:00 2004-02-01 00:00:00 drop table t1; +set sql_mode='maxdb'; +create table t1 (a timestamp, b timestamp(19)); +show create table t1; +Table Create Table +t1 CREATE TABLE "t1" ( + "a" datetime default NULL, + "b" datetime default NULL +) +set sql_mode=''; +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index c5147dc381e..a1fac51371c 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -279,6 +279,13 @@ select group_concat(distinct b order by b) from t1 group by a; drop table t1; # +# bug #7769: group_concat returning null is checked in having +# +CREATE TABLE t1 (id int); +SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; +DROP TABLE t1; + +# # Bug #6475 # diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test index 3f547739679..cb3ab12b5fc 100644 --- a/mysql-test/t/func_sapdb.test +++ b/mysql-test/t/func_sapdb.test @@ -60,6 +60,7 @@ select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +select timediff("2005-01-11 15:48:49.999999", "2005-01-11 15:48:50"); --enable_ps_protocol select maketime(10,11,12); diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 4b55593fde5..569d2f697c7 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -321,7 +321,6 @@ prepare stmt4 from ' show engine bdb logs '; execute stmt4; --enable_result_log prepare stmt4 from ' show full processlist '; ---replace_column 1 number 6 time execute stmt4; prepare stmt4 from ' show grants for user '; --error 1295 diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index a0cfc0c60f4..2ccc3e672c7 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -531,7 +531,7 @@ INSERT INTO t1 VALUES (-2.2E-307,0),(+1.7E+308,+1.7E+308); INSERT INTO t1 VALUES ('-2.2E-307',0),('+1.7E+308','+1.7E+308'); # We don't give warnings for underflow INSERT INTO t1 (col1) VALUES (-2.2E-330); ---error 1367 +--error 1367,1264 INSERT INTO t1 (col1) VALUES (+1.7E+309); --error 1264 INSERT INTO t1 (col2) VALUES (-1.1E-3); diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 69cdeaa32a9..d49f0465dfe 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -3,7 +3,7 @@ # Numeric floating point. --disable_warnings -drop table if exists t1; +drop table if exists t1,t2; --enable_warnings --replace_result e-0 e- e+0 e+ @@ -11,6 +11,7 @@ SELECT 10,10.0,10.,.1e+2,100.0e-1; --replace_result e-00 e-0 SELECT 6e-05, -6e-05, --6e-05, -6e-05+1.000000; SELECT 1e1,1.e1,1.0e1,1e+1,1.e+1,1.0e+1,1e-1,1.e-1,1.0e-1; +SELECT 0.001e+1,0.001e-1, -0.001e+01,-0.001e-01; create table t1 (f1 float(24),f2 float(52)); show full columns from t1; diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 0a92afeb57d..62e7510405d 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -288,3 +288,15 @@ insert into t1 values ('a', '2004-01-01 00:00:00'), ('a', '2004-01-01 01:00:00') ('b', '2004-02-01 00:00:00'); select max(t) from t1 group by a; drop table t1; + +# +# Test for bug #7418 "TIMESTAMP not always converted to DATETIME in MAXDB +# mode". TIMESTAMP columns should be converted DATETIME columns in MAXDB +# mode regardless of whether a display width is given. +# +set sql_mode='maxdb'; +create table t1 (a timestamp, b timestamp(19)); +show create table t1; +# restore default mode +set sql_mode=''; +drop table t1; diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index f109df912f1..b86e9daf92d 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -27,7 +27,7 @@ also info->read_pos is set to info->read_end. If called through open_cached_file(), then the temporary file will only be created if a write exeeds the file buffer or if one calls - flush_io_cache(). + my_b_flush_io_cache(). If one uses SEQ_READ_APPEND, then two buffers are allocated, one for reading and another for writing. Reads are first done from disk and @@ -43,7 +43,7 @@ TODO: each time the write buffer gets full and it's written to disk, we will always do a disk read to read a part of the buffer from disk to the read buffer. - This should be fixed so that when we do a flush_io_cache() and + This should be fixed so that when we do a my_b_flush_io_cache() and we have been reading the write buffer, we should transfer the rest of the write buffer to the read buffer before we start to reuse it. */ @@ -70,9 +70,40 @@ static void my_aiowait(my_aio_result *result); #define IO_ROUND_UP(X) (((X)+IO_SIZE-1) & ~(IO_SIZE-1)) #define IO_ROUND_DN(X) ( (X) & ~(IO_SIZE-1)) + +/* + Setup internal pointers inside IO_CACHE + + SYNOPSIS + setup_io_cache() + info IO_CACHE handler + + NOTES + This is called on automaticly on init or reinit of IO_CACHE + It must be called externally if one moves or copies an IO_CACHE + object. +*/ + +void setup_io_cache(IO_CACHE* info) +{ + /* Ensure that my_b_tell() and my_b_bytes_in_cache works */ + if (info->type == WRITE_CACHE) + { + info->current_pos= &info->write_pos; + info->current_end= &info->write_end; + } + else + { + info->current_pos= &info->read_pos; + info->current_end= &info->read_end; + } +} + + static void -init_functions(IO_CACHE* info, enum cache_type type) +init_functions(IO_CACHE* info) { + enum cache_type type= info->type; switch (type) { case READ_NET: /* @@ -96,17 +127,7 @@ init_functions(IO_CACHE* info, enum cache_type type) info->write_function = _my_b_write; } - /* Ensure that my_b_tell() and my_b_bytes_in_cache works */ - if (type == WRITE_CACHE) - { - info->current_pos= &info->write_pos; - info->current_end= &info->write_end; - } - else - { - info->current_pos= &info->read_pos; - info->current_end= &info->read_end; - } + setup_io_cache(info); } @@ -236,7 +257,7 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize, info->end_of_file= end_of_file; info->error=0; info->type= type; - init_functions(info,type); + init_functions(info); #ifdef HAVE_AIOWAIT if (use_async_io && ! my_disable_async_io) { @@ -339,7 +360,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, if (info->type == WRITE_CACHE && type == READ_CACHE) info->end_of_file=my_b_tell(info); /* flush cache if we want to reuse it */ - if (!clear_cache && flush_io_cache(info)) + if (!clear_cache && my_b_flush_io_cache(info,1)) DBUG_RETURN(1); info->pos_in_file=seek_offset; /* Better to do always do a seek */ @@ -358,7 +379,7 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, } info->type=type; info->error=0; - init_functions(info,type); + init_functions(info); #ifdef HAVE_AIOWAIT if (use_async_io && ! my_disable_async_io && @@ -948,7 +969,7 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) Buffer+=rest_length; Count-=rest_length; info->write_pos+=rest_length; - if (flush_io_cache(info)) + if (my_b_flush_io_cache(info,1)) return 1; if (Count >= IO_SIZE) { /* Fill first intern buffer */ @@ -1191,6 +1212,7 @@ int end_io_cache(IO_CACHE *info) int error=0; IO_CACHE_CALLBACK pre_close; DBUG_ENTER("end_io_cache"); + DBUG_PRINT("enter",("cache: 0x%lx", (ulong) info)); #ifdef THREAD /* @@ -1200,7 +1222,7 @@ int end_io_cache(IO_CACHE *info) */ if (info->share) { - pthread_cond_destroy (&info->share->cond); + pthread_cond_destroy(&info->share->cond); pthread_mutex_destroy(&info->share->mutex); info->share=0; } @@ -1215,7 +1237,7 @@ int end_io_cache(IO_CACHE *info) { info->alloced_buffer=0; if (info->file != -1) /* File doesn't exist */ - error=flush_io_cache(info); + error= my_b_flush_io_cache(info,1); my_free((gptr) info->buffer,MYF(MY_WME)); info->buffer=info->read_pos=(byte*) 0; } diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index d8c19d86e5c..c14b2899b4b 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -245,6 +245,19 @@ static inline void mark_blocks_free(MEM_ROOT* root) /* Deallocate everything used by alloc_root or just move used blocks to free list if called with MY_USED_TO_FREE + + SYNOPSIS + free_root() + root Memory root + MyFlags Flags for what should be freed: + + MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free + MY_KEEP_PREALLOC If this is not set, then free also the + preallocated block + + NOTES + One can call this function either with root block initialised with + init_alloc_root() or with a bzero()-ed block. */ void free_root(MEM_ROOT *root, myf MyFlags) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index d47ca8de183..9ce058f90fc 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -523,8 +523,10 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) data->prev=lock->write_wait.last; lock->write_wait.last= &data->next; data->cond=get_cond(); - if (lock->get_status) - (*lock->get_status)(data->status_param); + /* + We don't have to do get_status here as we will do it when we change + the delayed lock to a real write lock + */ statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } diff --git a/sql/field.cc b/sql/field.cc index 400ebf65273..084232fe2bb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1035,7 +1035,9 @@ int Field_decimal::store(longlong nr) double Field_decimal::val_real(void) { int not_used; - return my_strntod(&my_charset_bin, ptr, field_length, NULL, ¬_used); + char *end_not_used; + return my_strntod(&my_charset_bin, ptr, field_length, &end_not_used, + ¬_used); } longlong Field_decimal::val_int(void) @@ -4432,16 +4434,18 @@ int Field_string::store(longlong nr) double Field_string::val_real(void) { int not_used; - CHARSET_INFO *cs=charset(); - return my_strntod(cs,ptr,field_length,(char**)0,¬_used); + char *end_not_used; + CHARSET_INFO *cs= charset(); + return my_strntod(cs,ptr,field_length,&end_not_used,¬_used); } longlong Field_string::val_int(void) { int not_used; + char *end_not_used; CHARSET_INFO *cs=charset(); - return my_strntoll(cs,ptr,field_length,10,NULL,¬_used); + return my_strntoll(cs,ptr,field_length,10,&end_not_used,¬_used); } @@ -4740,8 +4744,9 @@ int Field_varstring::store(longlong nr) double Field_varstring::val_real(void) { int not_used; + char *end_not_used; uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); - return my_strntod(field_charset, ptr+length_bytes, length, (char**) 0, + return my_strntod(field_charset, ptr+length_bytes, length, &end_not_used, ¬_used); } @@ -4749,9 +4754,10 @@ double Field_varstring::val_real(void) longlong Field_varstring::val_int(void) { int not_used; + char *end_not_used; uint length= length_bytes == 1 ? (uint) (uchar) *ptr : uint2korr(ptr); - return my_strntoll(field_charset, ptr+length_bytes, length, 10, NULL, - ¬_used); + return my_strntoll(field_charset, ptr+length_bytes, length, 10, + &end_not_used, ¬_used); } @@ -5343,12 +5349,15 @@ int Field_blob::store(longlong nr) double Field_blob::val_real(void) { int not_used; - char *blob; + char *end_not_used, *blob; + uint32 length; + CHARSET_INFO *cs; + memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) return 0.0; - uint32 length=get_length(ptr); - CHARSET_INFO *cs=charset(); + length= get_length(ptr); + cs= charset(); return my_strntod(cs,blob,length,(char**)0, ¬_used); } diff --git a/sql/filesort.cc b/sql/filesort.cc index fc8e27c5f94..ecde74e5ec6 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -567,10 +567,10 @@ write_keys(SORTPARAM *param, register uchar **sort_keys, uint count, if (!my_b_inited(tempfile) && open_cached_file(tempfile, mysql_tmpdir, TEMP_PREFIX, DISK_BUFFER_SIZE, MYF(MY_WME))) - goto err; /* purecov: inspected */ + goto err; /* purecov: inspected */ buffpek.file_pos= my_b_tell(tempfile); if ((ha_rows) count > param->max_rows) - count=(uint) param->max_rows; /* purecov: inspected */ + count=(uint) param->max_rows; /* purecov: inspected */ buffpek.count=(ha_rows) count; for (end=sort_keys+count ; sort_keys != end ; sort_keys++) if (my_b_write(tempfile, (byte*) *sort_keys, (uint) rec_length)) @@ -841,6 +841,8 @@ int merge_many_buff(SORTPARAM *param, uchar *sort_buffer, if (flush_io_cache(to_file)) break; /* purecov: inspected */ temp=from_file; from_file=to_file; to_file=temp; + setup_io_cache(from_file); + setup_io_cache(to_file); *maxbuffer= (uint) (lastbuff-buffpek)-1; } close_cached_file(to_file); // This holds old result @@ -1173,7 +1175,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) else { sortorder->length=sortorder->field->pack_length(); - if (use_strnxfrm((cs=sortorder->field->charset()))) + /* + We must test cmp_type() to ensure that ENUM and SET are sorted + as numbers + */ + if (use_strnxfrm((cs=sortorder->field->charset())) && + sortorder->field->cmp_type() == STRING_RESULT) { sortorder->need_strxnfrm= 1; *multi_byte_charset= 1; diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index b5742699d7e..02d81882e7a 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -471,12 +471,24 @@ int ha_heap::create(const char *name, TABLE *table_arg, KEY_PART_INFO *key_part= pos->key_part; KEY_PART_INFO *key_part_end= key_part + pos->key_parts; - mem_per_row+= (pos->key_length + (sizeof(char*) * 2)); - keydef[key].keysegs= (uint) pos->key_parts; keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL)); keydef[key].seg= seg; - keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ? + + switch (pos->algorithm) { + case HA_KEY_ALG_UNDEF: + case HA_KEY_ALG_HASH: + keydef[key].algorithm= HA_KEY_ALG_HASH; + mem_per_row+= sizeof(char*) * 2; // = sizeof(HASH_INFO) + break; + case HA_KEY_ALG_BTREE: + keydef[key].algorithm= HA_KEY_ALG_BTREE; + mem_per_row+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*); + break; + default: + DBUG_ASSERT(0); // cannot happen + } + keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ? HA_KEY_ALG_HASH : pos->algorithm); for (; key_part != key_part_end; key_part++, seg++) @@ -525,8 +537,10 @@ int ha_heap::create(const char *name, TABLE *table_arg, hp_create_info.auto_key_type= auto_key_type; hp_create_info.auto_increment= (create_info->auto_increment_value ? create_info->auto_increment_value - 1 : 0); + hp_create_info.max_table_size=current_thd->variables.max_heap_table_size; + max_rows = (ha_rows) (hp_create_info.max_table_size / mem_per_row); error= heap_create(fn_format(buff,name,"","",4+2), - keys,keydef, share->reclength, + keys, keydef, share->reclength, (ulong) ((share->max_rows < max_rows && share->max_rows) ? share->max_rows : max_rows), diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e19071d599d..18ab6f42d28 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2425,6 +2425,8 @@ build_template( templ->mysql_col_len = (ulint) field->pack_length(); templ->type = get_innobase_type_from_mysql_type(field); + templ->charset = dtype_get_charset_coll_noninline( + index->table->cols[i].type.prtype); templ->is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG); if (templ->type == DATA_BLOB) { diff --git a/sql/item.cc b/sql/item.cc index c84496f8eb7..47dccf5b8da 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1290,11 +1290,12 @@ double Item_param::val_real() return (double) value.integer; case STRING_VALUE: case LONG_DATA_VALUE: - { - int dummy_err; - return my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), (char**) 0, &dummy_err); - } + { + int dummy_err; + char *end_not_used; + return my_strntod(str_value.charset(), (char*) str_value.ptr(), + str_value.length(), &end_not_used, &dummy_err); + } case TIME_VALUE: /* This works for example when user says SELECT ?+0.0 and supplies @@ -2545,8 +2546,9 @@ Item_num *Item_uint::neg() Item_real::Item_real(const char *str_arg, uint length) { int error; - char *end; - value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end, &error); + char *end_not_used; + value= my_strntod(&my_charset_bin, (char*) str_arg, length, &end_not_used, + &error); if (error) { /* @@ -3522,12 +3524,12 @@ void Item_cache_str::store(Item *item) double Item_cache_str::val_real() { DBUG_ASSERT(fixed == 1); - int err; + int err_not_used; + char *end_not_used; if (value) return my_strntod(value->charset(), (char*) value->ptr(), - value->length(), (char**) 0, &err); - else - return (double)0; + value->length(), &end_not_used, &err_not_used); + return (double) 0; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9e28acdd091..09b6d9cc35d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -58,17 +58,19 @@ uint nr_of_decimals(const char *str) return 0; } + double Item_str_func::val_real() { DBUG_ASSERT(fixed == 1); - int err; - char buff[64]; + int err_not_used; + char *end_not_used, buff[64]; String *res, tmp(buff,sizeof(buff), &my_charset_bin); res= val_str(&tmp); - return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), - NULL, &err) : 0.0; + return res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), + &end_not_used, &err_not_used) : 0.0; } + longlong Item_str_func::val_int() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 168c68ad706..be89aa3f86d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -591,14 +591,17 @@ void Item_sum_hybrid::clear() double Item_sum_hybrid::val_real() { DBUG_ASSERT(fixed == 1); - int err; if (null_value) return 0.0; switch (hybrid_type) { case STRING_RESULT: + { + char *end_not_used; + int err_not_used; String *res; res=val_str(&str_value); - return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(), - (char**) 0, &err) : 0.0); + return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), + &end_not_used, &err_not_used) : 0.0); + } case INT_RESULT: if (unsigned_flag) return ulonglong2double(sum_int); diff --git a/sql/item_sum.h b/sql/item_sum.h index 68899268b31..4d2bfe739c5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -783,9 +783,10 @@ class Item_func_group_concat : public Item_sum String *res; char *end_ptr; int error; - res= val_str(&str_value); + if (!(res= val_str(&str_value))) + return (longlong) 0; end_ptr= (char*) res->ptr()+ res->length(); - return res ? my_strtoll10(res->ptr(), &end_ptr, &error) : (longlong) 0; + return my_strtoll10(res->ptr(), &end_ptr, &error); } String* val_str(String* str); Item *copy_or_same(THD* thd); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6f569ea3ef4..322b38abe13 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -831,6 +831,7 @@ void wait_for_refresh(THD *thd); int open_tables(THD *thd, TABLE_LIST *tables, uint *counter); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); +bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 48855892567..ab59610f485 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1867,6 +1867,34 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) /* + Open all tables in list and process derived tables + + SYNOPSIS + open_normal_and_derived_tables + thd - thread handler + tables - list of tables for open&locking + + RETURN + FALSE - ok + TRUE - error + + NOTE + This is to be used on prepare stage when you don't read any + data from the tables. +*/ + +int open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables) +{ + uint counter; + DBUG_ENTER("open_normal_and_derived_tables"); + if (open_tables(thd, tables, &counter)) + DBUG_RETURN(-1); /* purecov: inspected */ + relink_tables_for_derived(thd); + DBUG_RETURN(mysql_handle_derived(thd->lex)); +} + + +/* Let us propagate pointers to open tables from global table list to table lists for multi-delete */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9e4f6c1334c..a71b8148f8e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -900,8 +900,12 @@ static bool mysql_test_insert(Prepared_statement *stmt, /* open temporary memory pool for temporary data allocated by derived tables & preparation procedure + Note that this is done without locks (should not be needed as we will not + access any data here) + If we would use locks, then we have to ensure we are not using + TL_WRITE_DELAYED as having two such locks can cause table corruption. */ - if (open_and_lock_tables(thd, table_list)) + if (open_normal_and_derived_tables(thd, table_list)) { DBUG_RETURN(TRUE); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b9c8f6c1237..0273334eca2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7823,12 +7823,17 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (temp_pool_slot != MY_BIT_NONE) // we got a slot sprintf(filename, "%s_%lx_%i", tmp_file_prefix, current_pid, temp_pool_slot); - else // if we run out of slots or we are not using tempool + else + { + /* if we run out of slots or we are not using tempool */ sprintf(filename,"%s%lx_%lx_%x",tmp_file_prefix,current_pid, thd->thread_id, thd->tmp_table++); + } - if (lower_case_table_names) - my_casedn_str(files_charset_info, path); + /* + No need for change table name to lower case as we are only creating + MyISAM or HEAP tables here + */ sprintf(path, "%s%s", mysql_tmpdir, filename); if (group) diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 533876b6718..e2c4b1289fd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -948,11 +948,12 @@ frm_type_enum mysql_frm_type(char *path) { DBUG_RETURN(FRMTYPE_ERROR); } - length= my_read(file, (byte*) header, 10, MYF(MY_WME)); + length= my_read(file, (byte*) header, sizeof(header), MYF(MY_WME)); my_close(file, MYF(MY_WME)); if (length == (int) MY_FILE_ERROR) DBUG_RETURN(FRMTYPE_ERROR); - if (!strncmp(header, "TYPE=VIEW\n", 10)) + if (length < (int) sizeof(header) || + !strncmp(header, "TYPE=VIEW\n", sizeof(header))) DBUG_RETURN(FRMTYPE_VIEW); DBUG_RETURN(FRMTYPE_TABLE); // Is probably a .frm table } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b1456dfbd3..cc2443bd41b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2793,7 +2793,7 @@ type: | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; } | DATE_SYM { $$=FIELD_TYPE_DATE; } | TIME_SYM { $$=FIELD_TYPE_TIME; } - | TIMESTAMP + | TIMESTAMP opt_len { if (YYTHD->variables.sql_mode & MODE_MAXDB) $$=FIELD_TYPE_DATETIME; @@ -2806,13 +2806,6 @@ type: $$=FIELD_TYPE_TIMESTAMP; } } - | TIMESTAMP '(' NUM ')' - { - LEX *lex= Lex; - lex->length= $3.str; - lex->type|= NOT_NULL_FLAG; - $$= FIELD_TYPE_TIMESTAMP; - } | DATETIME { $$=FIELD_TYPE_DATETIME; } | TINYBLOB { Lex->charset=&my_charset_bin; $$=FIELD_TYPE_TINY_BLOB; } diff --git a/sql/table.cc b/sql/table.cc index 97f17ea2417..71198993009 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -103,11 +103,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, O_RDONLY | O_SHARE, MYF(0))) < 0) - goto err_w_init; + goto err; error= 4; if (my_read(file,(byte*) head,64,MYF(MY_NABP))) - goto err_w_init; + goto err; if (memcmp(head, "TYPE=", 5) == 0) { @@ -116,9 +116,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (db_stat & NO_ERR_ON_NEW_FRM) DBUG_RETURN(5); - + file= -1; // caller can't process new .frm - goto err_w_init; + goto err; } share->blob_ptr_size= sizeof(char*); @@ -131,21 +131,21 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, share->path= strdup_root(&outparam->mem_root, name); outparam->alias= my_strdup(alias, MYF(MY_WME)); if (!share->table_name || !share->path || !outparam->alias) - goto err_not_open; + goto err; *fn_ext(share->table_name)='\0'; // Remove extension *fn_ext(share->path)='\0'; // Remove extension if (head[0] != (uchar) 254 || head[1] != 1 || (head[2] != FRM_VER && head[2] != FRM_VER+1 && ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ new_field_pack_flag=head[27]; new_frm_ver= (head[2] - FRM_VER); field_pack_length= new_frm_ver < 2 ? 11 : 17; error=3; if (!(pos=get_form_pos(file,head,(TYPELIB*) 0))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ *fn_ext(index_file)='\0'; // Remove .frm extension share->frm_version= head[2]; @@ -181,7 +181,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, key_info_length= (uint) uint2korr(head+28); VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0))); if (read_string(file,(gptr*) &disk_buff,key_info_length)) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ if (disk_buff[0] & 0x80) { share->keys= keys= (disk_buff[1] << 7) | (disk_buff[0] & 0x7f); @@ -201,7 +201,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO); if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root, n_length+uint2korr(disk_buff+4)))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ bzero((char*) keyinfo,n_length); outparam->key_info=keyinfo; key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys); @@ -210,7 +210,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ulong *rec_per_key; if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root, sizeof(ulong*)*key_parts))) - goto err_not_open; + goto err; for (i=0 ; i < keys ; i++, keyinfo++) { @@ -279,7 +279,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, /* Allocate handler */ if (!(outparam->file= get_new_handler(outparam, share->db_type))) - goto err_not_open; + goto err; error=4; outparam->reginfo.lock_type= TL_UNLOCK; @@ -296,14 +296,14 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, share->rec_buff_length= rec_buff_length; if (!(record= (char *) alloc_root(&outparam->mem_root, rec_buff_length * records))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ share->default_values= record; if (my_pread(file,(byte*) record, (uint) share->reclength, (ulong) (uint2korr(head+6)+ ((uint2korr(head+14) == 0xffff ? uint4korr(head+47) : uint2korr(head+14)))), MYF(MY_NABP))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ if (records == 1) { @@ -332,12 +332,13 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } #endif VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0))); - if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open; + if (my_read(file,(byte*) head,288,MYF(MY_NABP))) + goto err; if (crypted) { crypted->decode((char*) head+256,288-256); if (sint2korr(head+284) != 0) // Should be 0 - goto err_not_open; // Wrong password + goto err; // Wrong password } share->fields= uint2korr(head+258); @@ -359,13 +360,13 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, (share->fields+interval_parts+ keys+3)*sizeof(my_string)+ (n_length+int_length+com_length))))) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ outparam->field=field_ptr; read_length=(uint) (share->fields * field_pack_length + pos+ (uint) (n_length+int_length+com_length)); if (read_string(file,(gptr*) &disk_buff,read_length)) - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ if (crypted) { crypted->decode((char*) disk_buff,read_length); @@ -398,7 +399,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, uint count= (uint) (interval->count + 1) * sizeof(uint); if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root, count))) - goto err_not_open; + goto err; for (count= 0; count < interval->count; count++) interval->type_lengths[count]= strlen(interval->type_names[count]); interval->type_lengths[count]= 0; @@ -459,7 +460,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, charset= &my_charset_bin; #else error= 4; // unsupported field type - goto err_not_open; + goto err; #endif } else @@ -470,7 +471,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, { error= 5; // Unknown or unavailable charset errarg= (int) strpos[14]; - goto err_not_open; + goto err; } } if (!comment_length) @@ -543,7 +544,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (!reg_field) // Not supported field type { error= 4; - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ } reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT) @@ -616,7 +617,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, (uint) key_part->length); #ifdef EXTRA_DEBUG if (key_part->fieldnr > share->fields) - goto err_not_open; // sanity check + goto err; // sanity check #endif if (key_part->fieldnr) { // Should always be true ! @@ -767,7 +768,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, if (!(share->blob_field= save= (uint*) alloc_root(&outparam->mem_root, (uint) (share->blob_fields* sizeof(uint))))) - goto err_not_open; + goto err; for (i=0, ptr= outparam->field ; *ptr ; ptr++, i++) { if ((*ptr)->flags & BLOB_FLAG) @@ -779,25 +780,25 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, error=2; if (db_stat) { - int err; + int ha_err; unpack_filename(index_file,index_file); - if ((err=(outparam->file-> - ha_open(index_file, - (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR), - (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE : - ((db_stat & HA_WAIT_IF_LOCKED) || - (specialflag & SPECIAL_WAIT_IF_LOCKED)) ? - HA_OPEN_WAIT_IF_LOCKED : - (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ? - HA_OPEN_ABORT_IF_LOCKED : - HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))) + if ((ha_err= (outparam->file-> + ha_open(index_file, + (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR), + (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE : + ((db_stat & HA_WAIT_IF_LOCKED) || + (specialflag & SPECIAL_WAIT_IF_LOCKED)) ? + HA_OPEN_WAIT_IF_LOCKED : + (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ? + HA_OPEN_ABORT_IF_LOCKED : + HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags)))) { /* Set a flag if the table is crashed and it can be auto. repaired */ - share->crashed= ((err == HA_ERR_CRASHED_ON_USAGE) && + share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) && outparam->file->auto_repair() && !(ha_open_flags & HA_OPEN_FOR_REPAIR)); - if (err == HA_ERR_NO_SUCH_TABLE) + if (ha_err == HA_ERR_NO_SUCH_TABLE) { /* The table did not exists in storage engine, use same error message as if the .frm file didn't exist */ @@ -806,10 +807,10 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } else { - outparam->file->print_error(err, MYF(0)); + outparam->file->print_error(ha_err, MYF(0)); error_reported= TRUE; } - goto err_not_open; /* purecov: inspected */ + goto err; /* purecov: inspected */ } } share->db_low_byte_first= outparam->file->low_byte_first(); @@ -822,15 +823,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, #endif DBUG_RETURN (0); - err_w_init: - /* - Avoid problem with uninitialized data - Note that we don't have to initialize outparam->s here becasue - the caller will check if the pointer exists in case of errors - */ - bzero((char*) outparam,sizeof(*outparam)); - - err_not_open: + err: x_free((gptr) disk_buff); if (file > 0) VOID(my_close(file,MYF(MY_WME))); @@ -843,7 +836,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, outparam->file=0; // For easier errorchecking outparam->db_stat=0; hash_free(&share->name_hash); - free_root(&outparam->mem_root, MYF(0)); + free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root my_free((char*) outparam->alias, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN (error); } /* openfrm */ diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index f177ec84f60..804f87b2a5b 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -243,9 +243,10 @@ static int my_strnncoll_cp932(CHARSET_INFO *cs __attribute__((unused)), static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)), - const uchar *a, uint a_length, - const uchar *b, uint b_length, - my_bool diff_end_space __attribute__((unused))) + const uchar *a, uint a_length, + const uchar *b, uint b_length, + my_bool diff_if_only_endspace_difference + __attribute__((unused))) { const uchar *a_end= a + a_length; const uchar *b_end= b + b_length; diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 1df81c88258..bb623ef66f1 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -791,31 +791,10 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), char *str, uint length, char **end, int *err) { - char end_char; - double result; - - errno= 0; /* Safety */ - - /* - The following define is to avoid warnings from valgrind as str[length] - may not be defined (which is not fatal in real life) - */ - -#ifdef HAVE_purify if (length == INT_MAX32) -#else - if (length == INT_MAX32 || str[length] == 0) -#endif - result= my_strtod(str, end); - else - { - end_char= str[length]; - str[length]= 0; - result= my_strtod(str, end); - str[length]= end_char; /* Restore end char */ - } - *err= errno; - return result; + length= 65535; /* Should be big enough */ + *end= str + length; + return my_strtod(str, end, err); } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 6bd93a93e8a..adfd4794e36 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -926,15 +926,16 @@ bs: return (negative ? -((longlong) res) : (longlong) res); } -double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), - char *nptr, uint length, - char **endptr, int *err) + +double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), + char *nptr, uint length, + char **endptr, int *err) { char buf[256]; double res; register char *b=buf; register const uchar *s= (const uchar*) nptr; - register const uchar *end; + const uchar *end; my_wc_t wc; int cnv; @@ -951,13 +952,10 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), break; /* Can't be part of double */ *b++= (char) wc; } - *b= 0; - errno= 0; - res=my_strtod(buf, endptr); - *err= errno; - if (endptr) - *endptr=(char*) (*endptr-buf+nptr); + *endptr= b; + res= my_strtod(buf, endptr, err); + *endptr= nptr + (uint) (*endptr- buf); return res; } diff --git a/strings/strtod.c b/strings/strtod.c index bc8105b8040..92d93612dd0 100644 --- a/strings/strtod.c +++ b/strings/strtod.c @@ -2,7 +2,7 @@ An alternative implementation of "strtod()" that is both simplier, and thread-safe. - From mit-threads as bundled with MySQL 3.23 + Original code from mit-threads as bundled with MySQL 3.23 SQL:2003 specifies a number as @@ -29,6 +29,8 @@ #include "my_base.h" /* Includes errno.h */ #include "m_ctype.h" +#define MAX_DBL_EXP 308 +#define MAX_RESULT_FOR_MAX_EXP 1.79769313486232 static double scaler10[] = { 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 }; @@ -37,89 +39,154 @@ static double scaler1[] = { }; -double my_strtod(const char *str, char **end) +/* + Convert string to double (string doesn't have to be null terminated) + + SYNOPSIS + my_strtod() + str String to convert + end_ptr Pointer to pointer that points to end of string + Will be updated to point to end of double. + error Will contain error number in case of error (else 0) + + RETURN + value of str as double +*/ + +double my_strtod(const char *str, char **end_ptr, int *error) { double result= 0.0; - int negative, ndigits; - const char *old_str; + uint negative= 0, ndigits, dec_digits= 0, pre_zero, neg_exp= 0; + int exp= 0; + const char *old_str, *end= *end_ptr, *start_of_number; + char next_char; my_bool overflow=0; + *error= 0; + if (str >= end) + goto done; + while (my_isspace(&my_charset_latin1, *str)) - str++; + { + if (++str == end) + goto done; + } + start_of_number= str; if ((negative= (*str == '-')) || *str=='+') - str++; + { + if (++str == end) + goto done; /* Could be changed to error */ + } + + /* Skip pre-zero for easier calculation of overflows */ + while (*str == '0') + { + if (++str == end) + goto done; + start_of_number= 0; /* Found digit */ + } old_str= str; - while (my_isdigit (&my_charset_latin1, *str)) + while ((next_char= *str) >= '0' && next_char <= '9') { - result= result*10.0 + (*str - '0'); - str++; + result= result*10.0 + (next_char - '0'); + if (++str == end) + { + next_char= 0; /* Found end of string */ + break; + } + start_of_number= 0; /* Found digit */ } - ndigits= str-old_str; + ndigits= (uint) (str-old_str); - if (*str == '.') + pre_zero= 0; + if (next_char == '.' && str < end-1) { - double p10=10; - str++; - old_str= str; - while (my_isdigit (&my_charset_latin1, *str)) + double p10= 10; + old_str= ++str; + while (my_isdigit(&my_charset_latin1, (next_char= *str))) { - result+= (*str++ - '0')/p10; - p10*=10; + result+= (next_char - '0')/p10; + if (!result) + pre_zero++; + else + p10*= 10; + if (++str == end) + { + next_char= 0; + break; + } } - ndigits+= str-old_str; - if (!ndigits) str--; + /* If we found just '+.' or '.' then point at first character */ + if (!(dec_digits= (uint) (str-old_str)) && start_of_number) + str= start_of_number; /* Point at '+' or '.' */ } - if (ndigits && (*str=='e' || *str=='E')) + if ((next_char == 'e' || next_char == 'E') && + dec_digits + ndigits != 0 && str < end-1) { - int exp= 0; - int neg= 0; const char *old_str= str++; - if ((neg= (*str == '-')) || *str == '+') + if ((neg_exp= (*str == '-')) || *str == '+') str++; - if (!my_isdigit (&my_charset_latin1, *str)) + if (str == end || !my_isdigit(&my_charset_latin1, *str)) str= old_str; else { - double scaler= 1.0; - while (my_isdigit (&my_charset_latin1, *str)) + do { - if (exp < 9999) /* protection against exp overflow */ + if (exp < 9999) /* protec against exp overfl. */ exp= exp*10 + *str - '0'; str++; - } - if (exp >= 1000) + } while (str < end && my_isdigit(&my_charset_latin1, *str)); + } + } + if ((exp= neg_exp ? exp + pre_zero : exp - pre_zero)) + { + double scaler; + if (exp < 0) + { + exp= -exp; + neg_exp= 1; /* neg_exp was 0 before */ + } + if (exp + ndigits >= MAX_DBL_EXP + 1 && result) + { + /* + This is not 100 % as we actually will give an owerflow for + 17E307 but not for 1.7E308 but lets cut some corners to make life + simpler + */ + if (exp + ndigits > MAX_DBL_EXP + 1 || + result >= MAX_RESULT_FOR_MAX_EXP) { - if (neg) - result= 0.0; - else + if (neg_exp) + result= 0.0; + else overflow= 1; goto done; } - while (exp >= 100) - { - scaler*= 1.0e100; - exp-= 100; - } - scaler*= scaler10[exp/10]*scaler1[exp%10]; - if (neg) - result/= scaler; - else - result*= scaler; } + scaler= 1.0; + while (exp >= 100) + { + scaler*= 1.0e100; + exp-= 100; + } + scaler*= scaler10[exp/10]*scaler1[exp%10]; + if (neg_exp) + result/= scaler; + else + result*= scaler; } done: - if (end) - *end = (char *)str; + *end_ptr= (char*) str; /* end of number */ if (overflow || isinf(result)) { result= DBL_MAX; - errno= EOVERFLOW; + *error= EOVERFLOW; } return negative ? -result : result; @@ -127,6 +194,7 @@ done: double my_atof(const char *nptr) { - return (my_strtod(nptr, 0)); + int error; + const char *end= nptr+65535; /* Should be enough */ + return (my_strtod(nptr, (char**) &end, &error)); } - diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index cb35b844ff4..b7330d1e5d7 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -27,7 +27,7 @@ Packager: Lenz Grimmer <build@mysql.com> Vendor: MySQL AB Requires: fileutils sh-utils Provides: msqlormysql MySQL-server mysql -BuildPrereq: ncurses-devel +BuildRequires: ncurses-devel Obsoletes: mysql # Think about what you use here since the first step is to @@ -602,6 +602,10 @@ fi # itself - note that they must be ordered by date (important when # merging BK trees) %changelog +* Fri Jan 14 2005 Lenz Grimmer <lenz@mysql.com> + +- replaced obsoleted "BuildPrereq" with "BuildRequires" instead + * Thu Jan 13 2005 Lenz Grimmer <lenz@mysql.com> - enabled the "Federated" storage engine for the max binary |