From af4b5c896d3e8751e357c4fce5d2327ad55f41fe Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Feb 2005 15:17:17 +0100 Subject: [PATCH 01/12] Changes and fixes for windows compilation VC++Files/libmysqld/libmysqld.dsp: added sql/my_decimal.cc VC++Files/sql/mysqld.dsp: added my_decimal.cpp VC++Files/strings/strings.dsp: added decimal.c sql/field.cc: conversion fixes for windows compilation sql/item.h: fix for windows compilation sql/item_func.cc: fixed conversion for windows (cast from ulonglong to double is not supported) sql/item_sum.cc: typecast fix for windows compilation sql/sp_head.cc: typecast fix fo windows compilation sql/sql_cache.cc: typecast fix for windows compilation --- VC++Files/libmysqld/libmysqld.dsp | 4 ++++ VC++Files/sql/mysqld.dsp | 4 ++++ VC++Files/strings/strings.dsp | 4 ++++ sql/field.cc | 6 +++--- sql/item.h | 4 ++++ sql/item_func.cc | 2 +- sql/item_sum.cc | 4 ++-- sql/sp_head.cc | 2 +- sql/sql_cache.cc | 2 +- 9 files changed, 24 insertions(+), 8 deletions(-) diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp index 019589289cd..bb31a8ada43 100644 --- a/VC++Files/libmysqld/libmysqld.dsp +++ b/VC++Files/libmysqld/libmysqld.dsp @@ -344,6 +344,10 @@ SOURCE=..\mysys\my_alloc.c # End Source File # Begin Source File +SOURCE=..\mysys\my_decimal.cpp +# End Source File +# Begin Source File + SOURCE=..\mysys\my_getopt.c # End Source File # Begin Source File diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index e63d80d8697..5ca468f7fc9 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -1085,6 +1085,10 @@ SOURCE=.\mf_iocache.cpp # End Source File # Begin Source File +SOURCE=.\my_decimal.cpp +# End Source File +# Begin Source File + SOURCE=.\my_time.c # End Source File # Begin Source File diff --git a/VC++Files/strings/strings.dsp b/VC++Files/strings/strings.dsp index c8f3208e822..340617344f2 100644 --- a/VC++Files/strings/strings.dsp +++ b/VC++Files/strings/strings.dsp @@ -177,6 +177,10 @@ SOURCE=.\ctype.c # End Source File # Begin Source File +SOURCE=.\decimal.c +# End Source File +# Begin Source File + SOURCE=.\int2str.c # End Source File # Begin Source File diff --git a/sql/field.cc b/sql/field.cc index 0be72458701..1da9bf6f7b0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1581,10 +1581,10 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) DBUG_PRINT("info", ("overflow")); set_value_on_overflow(&buff, dec->sign()); my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals()); - DBUG_EXECUTE("info", print_decimal_buff(&buff, ptr, bin_size);); + DBUG_EXECUTE("info", print_decimal_buff(&buff, (byte *) ptr, bin_size);); DBUG_RETURN(1); } - DBUG_EXECUTE("info", print_decimal_buff(dec, ptr, bin_size);); + DBUG_EXECUTE("info", print_decimal_buff(dec, (byte *) ptr, bin_size);); DBUG_RETURN(error); } @@ -1708,7 +1708,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value, field_length, decimals()); - DBUG_EXECUTE("info", print_decimal_buff(decimal_value, ptr, bin_size);); + DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, bin_size);); DBUG_RETURN(decimal_value); } diff --git a/sql/item.h b/sql/item.h index 3e1844ec76e..2029337d5c4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -453,7 +453,11 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); +#ifdef __WIN__ + bool is_null(); +#else inline bool is_null(); +#endif void print(String *str); inline void make_field(Send_field *field) diff --git a/sql/item_func.cc b/sql/item_func.cc index 1e61474f412..1c03643a915 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1732,7 +1732,7 @@ longlong Item_func_round::int_op() if (truncate) { if (unsigned_flag) - tmp2= floor(((double)((ulonglong)value))/tmp)*tmp; + tmp2= floor(ulonglong2double(value)/tmp)*tmp; else if (value >= 0) tmp2= floor(((double)value)/tmp)*tmp; else diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2ecc1eb083c..3cfa1e4e37f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -578,7 +578,7 @@ bool Item_sum_sum_distinct::add() { DBUG_ASSERT(tree); null_value= 0; - my_decimal2binary(E_DEC_FATAL_ERROR, val, dec_bin_buff, + my_decimal2binary(E_DEC_FATAL_ERROR, val, (char *) dec_bin_buff, args[0]->max_length, args[0]->decimals); DBUG_RETURN(tree->unique_add(dec_bin_buff)); } @@ -613,7 +613,7 @@ void Item_sum_sum_distinct::add_real(double val) void Item_sum_sum_distinct::add_decimal(byte *val) { - binary2my_decimal(E_DEC_FATAL_ERROR, val, &tmp_dec, + binary2my_decimal(E_DEC_FATAL_ERROR, (char *) val, &tmp_dec, args[0]->max_length, args[0]->decimals); my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), &tmp_dec, dec_buffs + curr_dec_buff); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 075aef9d286..2ddd40bd22c 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2018,7 +2018,7 @@ sp_merge_table_hash(HASH *hdst, HASH *hsrc) SP_TABLE *tabsrc= (SP_TABLE *)hash_element(hsrc, i); if (! (tabdst= (SP_TABLE *)hash_search(hdst, - tabsrc->qname.str, + (byte *) tabsrc->qname.str, tabsrc->qname.length))) { my_hash_insert(hdst, (byte *)tabsrc); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b2f7922f1db..1f85d081d55 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1102,7 +1102,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) ("Handler require invalidation queries of %s.%s %lld-%lld", table_list.db, table_list.alias, engine_data, table->engine_data())); - invalidate_table(table->db(), table->key_length()); + invalidate_table((byte *) table->db(), table->key_length()); } else thd->lex->safe_to_cache_query= 0; // Don't try to cache this From a98179dcedd69a03554def1f9a018441efc15158 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Feb 2005 10:51:49 +0100 Subject: [PATCH 02/12] fix compilation errors sql/examples/ha_tina.cc: make tina to compile (wasn't catched with -max build) sql/sql_yacc.yy: fix compilation errors --without-geometry --- sql/examples/ha_tina.cc | 8 ++++---- sql/sql_yacc.yy | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 46a22614566..b515932d25f 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -647,7 +647,7 @@ int ha_tina::rnd_next(byte *buf) In the case of an order by rows will need to be sorted. ::position() is called after each call to ::rnd_next(), the data it stores is to a byte array. You can store this - data via ha_store_ptr(). ref_length is a variable defined to the + data via my_store_ptr(). ref_length is a variable defined to the class that is the sizeof() of position being stored. In our case its just a position. Look at the bdb code if you want to see a case where something other then a number is stored. @@ -655,14 +655,14 @@ int ha_tina::rnd_next(byte *buf) void ha_tina::position(const byte *record) { DBUG_ENTER("ha_tina::position"); - ha_store_ptr(ref, ref_length, current_position); + my_store_ptr(ref, ref_length, current_position); DBUG_VOID_RETURN; } /* Used to fetch a row from a posiion stored with ::position(). - ha_get_ptr() retrieves the data for you. + my_get_ptr() retrieves the data for you. */ int ha_tina::rnd_pos(byte * buf, byte *pos) @@ -670,7 +670,7 @@ int ha_tina::rnd_pos(byte * buf, byte *pos) DBUG_ENTER("ha_tina::rnd_pos"); statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status); - current_position= ha_get_ptr(pos,ref_length); + current_position= my_get_ptr(pos,ref_length); DBUG_RETURN(find_current_row(buf)); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5bc7f0e2bb9..04db57c5540 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2798,7 +2798,7 @@ type: Lex->uint_geom_type= (uint)$1; $$=FIELD_TYPE_GEOMETRY; #else - my_error(ER_FEATURE_DISABLED, MYF(0) + my_error(ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define); YYABORT; #endif @@ -3140,7 +3140,7 @@ opt_unique_or_fulltext: #ifdef HAVE_SPATIAL $$= Key::SPATIAL; #else - my_message(ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), MYF(0), + my_error(ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name, sym_group_geom.needed_define); YYABORT; #endif @@ -4259,8 +4259,6 @@ simple_expr: { $$= new Item_func_concat(* $3); } | CONCAT_WS '(' expr ',' expr_list ')' { $5->push_front($3); $$= new Item_func_concat_ws(*$5); } - | CONTAINS_SYM '(' expr ',' expr ')' - { $$= create_func_contains($3, $5); } | CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')' { if (Lex->add_time_zone_tables_to_query_tables(YYTHD)) @@ -4622,7 +4620,9 @@ simple_expr: { $$=new Item_extract( $3, $5); }; geometry_function: - GEOMFROMTEXT '(' expr ')' + CONTAINS_SYM '(' expr ',' expr ')' + { $$= GEOM_NEW(Item_func_spatial_rel($3, $5, Item_func::SP_CONTAINS_FUNC)); } + | GEOMFROMTEXT '(' expr ')' { $$= GEOM_NEW(Item_func_geometry_from_text($3)); } | GEOMFROMTEXT '(' expr ',' expr ')' { $$= GEOM_NEW(Item_func_geometry_from_text($3, $5)); } From 0bc02450a61180a5827ce4ab2a2b3538c1c1ce91 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Feb 2005 12:15:30 +0100 Subject: [PATCH 03/12] windows compilation fixes --- include/config-win.h | 3 +++ include/my_sys.h | 3 ++- sql/ha_berkeley.cc | 1 + sql/ha_innodb.cc | 6 +++--- sql/handler.cc | 2 +- sql/log.cc | 12 +++++++----- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 9918f69a978..475141a1989 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -353,6 +353,8 @@ inline double ulonglong2double(ulonglong value) #define DO_NOT_REMOVE_THREAD_WRAPPERS #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) +#define thread_safe_decrement(V,L) InterlockedDecrement((long*) &(V)) +#define thread_safe_dec_and_test(V, L) thread_safe_decrement(V,L) /* The following is only used for statistics, so it should be good enough */ #ifdef __NT__ /* This should also work on Win98 but .. */ #define thread_safe_add(V,C,L) InterlockedExchangeAdd((long*) &(V),(C)) @@ -366,6 +368,7 @@ inline double ulonglong2double(ulonglong value) #define statistic_add(V,C,L) (V)+=(C) #endif #define statistic_increment(V,L) thread_safe_increment((V),(L)) +#define statistic_decrement(V,L) thread_safe_decrement((V),(L)) #define shared_memory_buffer_length 16000 #define default_shared_memory_base_name "MYSQL" diff --git a/include/my_sys.h b/include/my_sys.h index 72d4bec74b1..9cce13e53dd 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -811,7 +811,8 @@ my_bool my_gethwaddr(uchar *to); /* not a complete set of mmap() flags, but only those that nesessary */ #define PROT_READ 1 #define PROT_WRITE 2 -#define MAP_NOSYNC 0x800 +#define MAP_SHARED 0x0001 +#define MAP_NOSYNC 0x0800 #define MAP_FAILED ((void *)-1) #define MS_SYNC 0x0000 diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 6c26a9555a6..f8e14844875 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -215,6 +215,7 @@ bool berkeley_end(void) static int berkeley_close_connection(THD *thd) { my_free((gptr)thd->ha_data[berkeley_hton.slot], MYF(0)); + return 0; } bool berkeley_flush_logs() diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 2199d958bb6..fd275b19f77 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2652,7 +2652,7 @@ ha_innobase::write_row( no need to re-acquire locks on it. */ /* Altering to InnoDB format */ - innobase_commit(user_thd, prebuilt->trx); + innobase_commit(user_thd, 1); /* Note that this transaction is still active. */ prebuilt->trx->active_trans = 1; /* We will need an IX lock on the destination table. */ @@ -2667,7 +2667,7 @@ ha_innobase::write_row( /* Commit the transaction. This will release the table locks, so they have to be acquired again. */ - innobase_commit(user_thd, prebuilt->trx); + innobase_commit(user_thd, 1); /* Note that this transaction is still active. */ prebuilt->trx->active_trans = 1; /* Re-acquire the table lock on the source table. */ @@ -4247,7 +4247,7 @@ ha_innobase::delete_all_rows(void) goto fallback; } - innobase_commit(thd, trx); + innobase_commit(thd, 1); error = convert_error_code_to_mysql(error, NULL); diff --git a/sql/handler.cc b/sql/handler.cc index d1331243361..3ccea502a50 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -757,7 +757,7 @@ int ha_recover(HASH *commit_list) if (!x) // not "mine" - that is generated by external TM continue; if (commit_list ? - hash_search(commit_list, (char *)&x, sizeof(x)) != 0 : + hash_search(commit_list, (byte *)&x, sizeof(x)) != 0 : tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT) (*(*ht)->commit_by_xid)(list+i); else diff --git a/sql/log.cc b/sql/log.cc index 7d6f2abb022..cb776cff0e9 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2096,7 +2096,7 @@ void MYSQL_LOG::close(uint exiting) if (log_file.type == WRITE_CACHE && log_type == LOG_BIN) { my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET; - char flags=0; // clearing LOG_EVENT_BINLOG_IN_USE_F + byte flags=0; // clearing LOG_EVENT_BINLOG_IN_USE_F my_pwrite(log_file.file, &flags, 1, offset, MYF(0)); } @@ -2474,10 +2474,10 @@ int TC_LOG_MMAP::open(const char *opt_name) DBUG_ASSERT(opt_name && opt_name[0]); #ifdef HAVE_GETPAGESIZE - tc_log_page_size=getpagesize(); + tc_log_page_size= my_getpagesize(); DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0); #else - tc_log_page_size=TC_LOG_PAGE_SIZE; + tc_log_page_size= TC_LOG_PAGE_SIZE; #endif fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME); @@ -2781,6 +2781,7 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) void TC_LOG_MMAP::close() { + uint i; switch (inited) { case 6: pthread_mutex_destroy(&LOCK_sync); @@ -2790,7 +2791,7 @@ void TC_LOG_MMAP::close() case 5: data[0]='A'; // garble the first (signature) byte, in case my_delete fails case 4: - for (uint i=0; i < npages; i++) + for (i=0; i < npages; i++) { if (pages[i].ptr == 0) break; @@ -3015,7 +3016,8 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) if (ev->get_type_code() == XID_EVENT) { Xid_log_event *xev=(Xid_log_event *)ev; - byte *x=memdup_root(&mem_root, (char *)& xev->xid, sizeof(xev->xid)); + byte *x=(byte *)memdup_root(&mem_root, (char *)& xev->xid, + sizeof(xev->xid)); if (! x) goto err2; my_hash_insert(&xids, x); From 64cc538bda5908e2688a1ba08a9ff156971a102b Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Feb 2005 18:58:27 +0200 Subject: [PATCH 04/12] Fixed BUILD script to use --with-berkeley-db instead of --with-bdb Lots of small fixes to multi-precision-math path Give Note for '123.4e' Added helper functions type 'val_string_from_real() Don't give warnings for end space for string2decimal() Changed storage of values for SP so that we can detect length of argument without strlen() Changed interface for str2dec() so that we must supple the pointer to the last character in the buffer BUILD/SETUP.sh: with-bdb ->with-berkeley-db include/decimal.h: Make string2decimal and string2decimal_fixed inline mysql-test/r/func_group.result: More tests (to find bugs in precision math fixes) mysql-test/r/func_set.result: Test to cover more Item_func_field::val_xxx() code mysql-test/r/ps_6bdb.result: update results mysql-test/r/type_decimal.result: New tests Give note for '123.4e' mysql-test/r/type_newdecimal.result: Number of decimal changes (probably right, but hard to verify) mysql-test/t/func_group.test: More tests (to find bugs in precision math fixes) mysql-test/t/func_set.test: Test to cover more Item_func_field::val_xxx() code mysql-test/t/type_decimal.test: New tests to cover more cases in decimal.c sql/item.cc: Added helper functions type 'val_string_from_real()' Use new interfase to str2my_decimal() Moved nr_of_decimals() here (and made it static) sql/item.h: Added helper functions type 'val_string_from_real()' sql/item_func.cc: Style fixes Trivial optimizations Ensure null_value is set if my_decimal_add/sub/mul/div returns error Remove not needed Item_func_int_div::val_str() Join Item_func_signproc and Item_func_neg Fix that FIELD() works when first argument is NULL or one if it's arguments are NULL new str2my_decimal interface sql/item_func.h: Make Item_func_int_div inherit from Item_int_func (allows us to remove some virtual functions) Join Item_func_signproc & Item_func_neg sql/item_strfunc.cc: Move nr_of_decmails() to Item.cc (as it was only used here) sql/item_sum.cc: Style fixes Change a lot of code to use new helper converter functions in item.cc Moved Item_sum::val_decimal() to Item_sum_int::val_decimal() Fixed calls to wrong functions (Item_sum_num::val_int()) Ensure that all hybrid functions checks hybrid_type in val_xxx() (As there is no gurantee that they are called in the right context) Simplify key_length allocation in Item_sum_sum_distinct() Simplified create_tmp_field() and reset_field() Fixed potential error in Item_sum_hybrid::reset_field() Optimize Item_sum_avg::update_field() Item_std_field() functions musted be fully coded becasue Item_variance_field::val_xxx functions called helper functions Coded missing Item_sum_ufd_xxx::val_decimal() functions sql/item_sum.h: Moved Item_sum::val_decimal() to Item_sum_int::val_decimal() Added missing Item_sum_ufd_xxx::val_decimal() functions Removed not used scale() function. Fixed that Item_std_field() works with decimal arguments Fixed that CREATE ... STD() will create a REAL field sql/log_event.cc: Ensure that we use same format for all types sql/my_decimal.cc: Don't give warnings for end space for string2decimal() Added dbug_print_decimal() sql/my_decimal.h: Style fixes Prototypes for new functions New interface for str2my_decimal() sql/mysql_priv.h: Made nr_of_decimals() static sql/protocol.cc: Simplify code (by assume that decimal can't be bigger than DECIMAL_MAX_STR_LENGTH] sql/protocol_cursor.cc: Changed storage of values for SP so that we can detect length of argument without strlen() sql/sp_head.cc: Simplify code for decimal handling by letting item handling conversion to decimal sql/sp_rcontext.cc: Use new method to get length of arguments sql/sql_analyse.cc: if -> switch Increase 'empty' if decimal value=0 Remove usage of strcat() sql/sql_base.cc: Remove unnecessary checks sql/sql_class.cc: Remove not needed 'else' Removed not used variables sql/sql_select.cc: remove test for impossible condtion strings/decimal.c: Made two trivial functions macros Changed interface for str2dec() so that we must supple the pointer to the last character in the buffer This safer than before as we don't require an end \0 anymore (old code gave wrong answers in MySQL for some internals strings that where not \0 terminated) Detect error numbers of type '12.55e' str2dec() will now set 'to' to zero in case of errors --- BUILD/SETUP.sh | 4 +- include/decimal.h | 13 +- mysql-test/r/func_group.result | 20 + mysql-test/r/func_set.result | 6 + mysql-test/r/ps_6bdb.result | 2 - mysql-test/r/type_decimal.result | 23 ++ mysql-test/r/type_newdecimal.result | 2 +- mysql-test/t/func_group.test | 5 + mysql-test/t/func_set.test | 2 + mysql-test/t/type_decimal.test | 3 + sql/item.cc | 123 +++++- sql/item.h | 10 + sql/item_func.cc | 182 ++++----- sql/item_func.h | 21 +- sql/item_strfunc.cc | 13 - sql/item_sum.cc | 555 +++++++++++++--------------- sql/item_sum.h | 15 +- sql/log_event.cc | 2 +- sql/my_decimal.cc | 35 +- sql/my_decimal.h | 56 +-- sql/mysql_priv.h | 2 - sql/protocol.cc | 24 +- sql/protocol_cursor.cc | 9 +- sql/sp_head.cc | 72 +--- sql/sp_rcontext.cc | 27 +- sql/sql_analyse.cc | 43 ++- sql/sql_base.cc | 7 +- sql/sql_class.cc | 33 +- sql/sql_select.cc | 5 +- strings/decimal.c | 233 +++++++----- 30 files changed, 857 insertions(+), 690 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index b899b9a7d9b..403857f403f 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -48,8 +48,8 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" -base_max_configs="--with-innodb --with-bdb --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio" -max_leave_isam_configs="--with-innodb --with-bdb --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server" +base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio" +max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server" max_no_es_configs="$max_leave_isam_configs --without-isam" max_configs="$max_no_es_configs --with-embedded-server" diff --git a/include/decimal.h b/include/decimal.h index 1e0ee97c267..3f4a2122c57 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -17,7 +17,9 @@ #ifndef _decimal_h #define _decimal_h -typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode; +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; typedef int32 decimal_digit; typedef struct st_decimal { @@ -26,11 +28,10 @@ typedef struct st_decimal { decimal_digit *buf; } decimal; +int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed); int decimal2string(decimal *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler); -int string2decimal(char *from, decimal *to, char **end); -int string2decimal_fixed(char *from, decimal *to, char **end); int decimal2ulonglong(decimal *from, ulonglong *to); int ulonglong2decimal(ulonglong from, decimal *to); int decimal2longlong(decimal *from, longlong *to); @@ -51,10 +52,14 @@ int decimal_cmp(decimal *from1, decimal *from2); int decimal_mul(decimal *from1, decimal *from2, decimal *to); int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr); int decimal_mod(decimal *from1, decimal *from2, decimal *to); -int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode mode); +int decimal_round(decimal *from, decimal *to, int new_scale, + decimal_round_mode mode); int decimal_is_zero(decimal *from); void max_decimal(int precision, int frac, decimal *to); +#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) +#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) + /* set a decimal to zero */ #define decimal_make_zero(dec) do { \ diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index fdadd378ceb..0ad992b87e5 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -90,6 +90,26 @@ id avg(rating) 1 3.0000 2 NULL 3 2.0000 +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.0000 +2 NULL +3 2.0000 +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.0000 +2 NULL +3 2.0000 +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 drop table t1,t2; create table t1 (a smallint(6) primary key, c char(10), b text); INSERT INTO t1 VALUES (1,'1','1'); diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index ca6e0a8c319..aa71cee0752 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -30,6 +30,12 @@ Y-N-N-Y-N Y,N,N,Y,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, select elt(2,1),field(NULL,"a","b","c"); elt(2,1) field(NULL,"a","b","c") NULL 0 +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +field("b","a",NULL) field(1,0,NULL)+0 field(1.0,0.0,NULL)+0.0 field(1.0e1,0.0e1,NULL)+0.0e1 +0 0 0.0 0 +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; +field(NULL,"a",NULL) field(NULL,0,NULL)+0 field(NULL,0.0,NULL)+0.0 field(NULL,0.0e1,NULL)+0.0e1 +0 0 0.0 0 select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c") 0 4 1 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index bf7ef64d052..c02215ad750 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -2674,7 +2674,6 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 -Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2725,7 +2724,6 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 -Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -1 diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 2045b7e65dd..6c4a1fab857 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -169,8 +169,19 @@ Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1366 Incorrect decimal value: '1e+18446744073709551616' for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 3 +Warning 1366 Incorrect decimal value: '1e-9223372036854775809' for column 'a' at row 4 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -195,6 +206,12 @@ a 99999999.99 0.00 -99999999.99 +99999999.99 +0.00 +99999999.99 +0.00 +0.00 +0.00 123.40 12340.00 1.23 @@ -229,6 +246,7 @@ Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -287,6 +305,7 @@ Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -338,6 +357,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); Warnings: Note 1265 Data truncated for column 'a' at row 3 +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); select * from t1; a 0.00 @@ -366,6 +386,9 @@ a 1.23 1230.00 123.00 +98.00 +987.00 +98760.00 drop table t1; create table t1 (a decimal); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index cf23d4162ae..5b6612572cb 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -696,7 +696,7 @@ end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;// call p1()// # v1 v2 v3 * 0.000000000001 v4 * 0.000000000001 -1.000000100000 1.999999900000 1.000000100000000000 1.999999900000000000 +1.000000100000 1.999999900000 1.000000100000 1.999999900000 drop procedure p1; drop table if exists t1; Warnings: diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index a47218e5c01..60eefe2a104 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -58,6 +58,11 @@ create table t2 (id int not null,rating int null); insert into t1 values(1),(2),(3); insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL); select t1.id, avg(rating) from t1 left join t2 on ( t1.id = t2.id ) group by t1.id; +# Test different types with avg() +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; drop table t1,t2; # diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 98ef1e07bfe..0c79dec7cc2 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -18,6 +18,8 @@ select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N","" # Wrong usage of functions # select elt(2,1),field(NULL,"a","b","c"); +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc"); select interval(null, 1, 10, 100); diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 414a06deaa9..6f170a52700 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -165,6 +165,8 @@ insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); select * from t1; drop table t1; @@ -201,6 +203,7 @@ insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); insert into t1 values (1e+100),(1e-100),(-1e+100); insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); select * from t1; drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 4eb4e017ef2..33e6d7cfc42 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -73,6 +73,99 @@ bool Item::val_bool() } +String *Item::val_string_from_real(String *str) +{ + double nr= val_real(); + if (null_value) + return 0; /* purecov: inspected */ + str->set(nr,decimals, &my_charset_bin); + return str; +} + + +String *Item::val_string_from_int(String *str) +{ + longlong nr= val_int(); + if (null_value) + return 0; + if (unsigned_flag) + str->set((ulonglong) nr, &my_charset_bin); + else + str->set(nr, &my_charset_bin); + return str; +} + + +String *Item::val_string_from_decimal(String *str) +{ + my_decimal dec_buf, *dec= val_decimal(&dec_buf); + if (null_value) + return 0; + my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str); + return str; +} + + +my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value) +{ + double nr= val_real(); + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return (decimal_value); +} + + +my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value) +{ + longlong nr= val_int(); + if (null_value) + return 0; + int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value); + return decimal_value; +} + + +my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) +{ + String *res; + char *end_ptr; + int error; + if (!(res= val_str(&str_value))) + return 0; // NULL or EOM + + end_ptr= (char*) res->ptr()+ res->length(); + str2my_decimal(E_DEC_FATAL_ERROR, res->ptr(), res->length(), res->charset(), + decimal_value); + return decimal_value; +} + + +double Item::val_real_from_decimal() +{ + /* Note that fix_fields may not be called for Item_avg_field items */ + double result; + my_decimal value_buff, *dec_val= val_decimal(&value_buff); + if (null_value) + return 0.0; + my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result); + return result; +} + + +longlong Item::val_int_from_decimal() +{ + /* Note that fix_fields may not be called for Item_avg_field items */ + longlong result; + my_decimal value, *dec_val= val_decimal(&value); + if (null_value) + return 0; + my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result); + return result; +} + + Item::Item(): name(0), orig_name(0), name_length(0), fixed(0), collation(&my_charset_bin, DERIVATION_COERCIBLE) @@ -1376,11 +1469,14 @@ void Item_param::set_double(double d) binary protocol, we use str2my_decimal to convert it to internal decimal value. */ + void Item_param::set_decimal(const char *str, ulong length) { + char *end; DBUG_ENTER("Item_param::set_decimal"); - str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value); + end= (char*) str+length; + str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end); state= DECIMAL_VALUE; decimals= decimal_value.frac; max_length= decimal_value.intg + decimals + 2; @@ -3012,6 +3108,29 @@ Item_num *Item_uint::neg() } +static uint nr_of_decimals(const char *str, const char *end) +{ + const char *decimal_point; + + /* Find position for '.' */ + for (;;) + { + if (str == end) + return 0; + if (*str == 'e' || *str == 'E') + return NOT_FIXED_DEC; + if (*str++ == '.') + break; + } + decimal_point= str; + for (; my_isdigit(system_charset_info, *str) ; str++) + ; + if (*str == 'e' || *str == 'E') + return NOT_FIXED_DEC; + return (uint) (str - decimal_point); +} + + /* This function is only called during parsing. We will signal an error if value is not a true double value (overflow) @@ -3033,7 +3152,7 @@ Item_float::Item_float(const char *str_arg, uint length) my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg); } presentation= name=(char*) str_arg; - decimals=(uint8) nr_of_decimals(str_arg); + decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); max_length=length; fixed= 1; } diff --git a/sql/item.h b/sql/item.h index 299bc6c081b..d12da37627d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -276,6 +276,16 @@ public: TRUE value is true (not equal to 0) */ bool val_bool(); + /* Helper functions, see item_sum.cc */ + String *val_string_from_real(String *str); + String *val_string_from_int(String *str); + String *val_string_from_decimal(String *str); + my_decimal *val_decimal_from_real(my_decimal *decimal_value); + my_decimal *val_decimal_from_int(my_decimal *decimal_value); + my_decimal *val_decimal_from_string(my_decimal *decimal_value); + longlong val_int_from_decimal(); + double val_real_from_decimal(); + 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 : "???"; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 1e61474f412..43481db7b56 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -714,15 +714,14 @@ void Item_num_op::find_num_type(void) SYNOPSIS Item_func_num1::find_num_type() */ + void Item_func_num1::find_num_type() { DBUG_ENTER("Item_func_num1::find_num_type"); DBUG_PRINT("info", ("name %s", func_name())); - switch(hybrid_type= args[0]->result_type()) - { + switch (hybrid_type= args[0]->result_type()) { case INT_RESULT: - unsigned_flag=args[0]->unsigned_flag; - hybrid_type= INT_RESULT; + unsigned_flag= args[0]->unsigned_flag; break; case STRING_RESULT: case REAL_RESULT: @@ -730,7 +729,6 @@ void Item_func_num1::find_num_type() max_length= float_length(decimals); break; case DECIMAL_RESULT: - hybrid_type= DECIMAL_RESULT; break; default: DBUG_ASSERT(0); @@ -761,13 +759,12 @@ void Item_func_numhybrid::fix_length_and_dec() String *Item_func_numhybrid::val_str(String *str) { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; if (!(val= decimal_op(&decimal_value))) - return 0; + return 0; // null is set my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); break; @@ -785,7 +782,7 @@ String *Item_func_numhybrid::val_str(String *str) } case REAL_RESULT: { - double nr=real_op(); + double nr= real_op(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); @@ -801,14 +798,13 @@ String *Item_func_numhybrid::val_str(String *str) double Item_func_numhybrid::val_real() { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; - if (!(val= decimal_op(&decimal_value))) - return 0.0; double result; + if (!(val= decimal_op(&decimal_value))) + return 0.0; // null is set my_decimal2double(E_DEC_FATAL_ERROR, val, &result); return result; } @@ -826,13 +822,12 @@ double Item_func_numhybrid::val_real() longlong Item_func_numhybrid::val_int() { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; if (!(val= decimal_op(&decimal_value))) - return 0; + return 0; // null is set longlong result; my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); return result; @@ -852,8 +847,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) { my_decimal *val= decimal_value; DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: val= decimal_op(decimal_value); break; @@ -949,14 +943,29 @@ longlong Item_func_plus::int_op() } +/* + Calculate plus of two decimail's + + SYNOPSIS + decimal_op() + decimal_value Buffer that can be used to store result + + RETURN + 0 Value was NULL; In this case null_value is set + # Value of operation as a decimal +*/ + my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); - if ((null_value= args[1]->null_value) || - my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) return 0; return decimal_value; } @@ -1008,14 +1017,20 @@ longlong Item_func_minus::int_op() } +/* See Item_func_plus::decimal_op for comments */ + my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2= + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); - if ((null_value= args[1]->null_value) || - my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) return 0; return decimal_value; } @@ -1041,14 +1056,19 @@ longlong Item_func_mul::int_op() } +/* See Item_func_plus::decimal_op for comments */ + my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); - if ((null_value= args[1]->null_value) || - my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) return 0; return decimal_value; } @@ -1081,21 +1101,24 @@ double Item_func_div::real_op() my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); + val2= args[1]->val_decimal(&value2); if ((null_value= args[1]->null_value)) return 0; switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, - val1, val2, DECIMAL_DIV_SCALE_INCREASE)) - { + val1, val2, DECIMAL_DIV_SCALE_INCREASE)) { case E_DEC_TRUNCATED: case E_DEC_OK: return decimal_value; case E_DEC_DIV_ZERO: signal_divide_by_null(); default: + null_value= 1; // Safety return 0; } } @@ -1115,8 +1138,7 @@ void Item_func_div::fix_length_and_dec() { DBUG_ENTER("Item_func_div::fix_length_and_dec"); Item_num_op::fix_length_and_dec(); - switch(hybrid_type) - { + switch(hybrid_type) { case REAL_RESULT: { decimals=max(args[0]->decimals,args[1]->decimals)+2; @@ -1148,7 +1170,7 @@ longlong Item_func_int_div::val_int() DBUG_ASSERT(fixed == 1); longlong value=args[0]->val_int(); longlong val2=args[1]->val_int(); - if (args[0]->null_value || args[1]->null_value) + if ((null_value= (args[0]->null_value || args[1]->null_value))) return 0; if (val2 == 0) { @@ -1161,19 +1183,6 @@ longlong Item_func_int_div::val_int() } -String *Item_func_int_div::val_str(String*str) -{ - longlong nr= val_int(); - if (null_value) - return 0; /* purecov: inspected */ - if (!unsigned_flag) - str->set(nr,&my_charset_bin); - else - str->set((ulonglong) nr,&my_charset_bin); - return str; -} - - void Item_func_int_div::fix_length_and_dec() { max_length=args[0]->max_length - args[0]->decimals; @@ -1215,21 +1224,24 @@ double Item_func_mod::real_op() my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); + val2= args[1]->val_decimal(&value2); if ((null_value= args[1]->null_value)) return 0; switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, - val1, val2)) - { + val1, val2)) { case E_DEC_TRUNCATED: case E_DEC_OK: return decimal_value; case E_DEC_DIV_ZERO: signal_divide_by_null(); default: + null_value= 1; return 0; } } @@ -1279,24 +1291,23 @@ void Item_func_neg::fix_num_length_and_dec() } -void Item_func_signproc::fix_length_and_dec() +void Item_func_neg::fix_length_and_dec() { - DBUG_ENTER("Item_func_signproc::fix_length_and_dec"); + DBUG_ENTER("Item_func_neg::fix_length_and_dec"); Item_func_num1::fix_length_and_dec(); + + /* + If this is in integer context keep the context as integer if possible + (This is how multiplication and other integer functions works) + */ if (hybrid_type == INT_RESULT && args[0]->type() == INT_ITEM && ((ulonglong) ((Item_uint*) args[0])->value >= (ulonglong) LONGLONG_MIN)) { /* - If this is in integer context keep the context as integer - (This is how multiplication and other integer functions works) - - We must however do a special case in the case where the argument - is a unsigned bigint constant as in this case the only safe - number to convert in integer context is 9223372036854775808. - (This is needed because the lex parser doesn't anymore handle - signed integers) + Ensure that result is converted to DECIMAL, as longlong can't hold + the negated number */ hybrid_type= DECIMAL_RESULT; DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); @@ -1618,9 +1629,9 @@ double Item_func_ceiling::real_op() my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) { my_decimal val, *value= args[0]->val_decimal(&val); - if ((null_value= args[0]->null_value)) - return 0; - if (my_decimal_ceiling(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + if ((null_value= (args[0]->null_value || + my_decimal_ceiling(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) return 0; return decimal_value; } @@ -1653,9 +1664,9 @@ double Item_func_floor::real_op() my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) { my_decimal val, *value= args[0]->val_decimal(&val); - if ((null_value= args[0]->null_value)) - return 0; - if (my_decimal_floor(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + if ((null_value= (args[0]->null_value || + my_decimal_floor(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) return 0; return decimal_value; } @@ -1750,10 +1761,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) int dec=(int) args[1]->val_int(); if (dec > 0) decimals= dec; // to get correct output - if ((null_value= args[0]->null_value || args[1]->null_value)) - return 0; - if (my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, - decimal_value) > 1) + if ((null_value= (args[0]->null_value || args[1]->null_value || + my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, + decimal_value) > 1))) return 0; return decimal_value; } @@ -2125,9 +2135,11 @@ longlong Item_func_field::val_int() else if (cmp_type == INT_RESULT) { longlong val= args[0]->val_int(); + if (args[0]->is_null()) + return 0; for (uint i=1; i < arg_count ; i++) { - if (val == args[i]->val_int()) + if (val == args[i]->val_int() && ! args[i]->is_null()) return (longlong) (i); } } @@ -2140,18 +2152,18 @@ longlong Item_func_field::val_int() for (uint i=1; i < arg_count; i++) { dec_arg= args[i]->val_decimal(&dec_arg_buf); - if (args[i]->is_null()) - continue; - if (!my_decimal_cmp(dec_arg, dec)) + if (!args[i]->is_null() && !my_decimal_cmp(dec_arg, dec)) return (longlong) (i); } } else { double val= args[0]->val_real(); + if (args[0]->is_null()) + return 0; for (uint i=1; i < arg_count ; i++) { - if (val == args[i]->val_real()) + if (val == args[i]->val_real() && ! args[i]->is_null()) return (longlong) (i); } } @@ -2589,6 +2601,10 @@ String *udf_handler::val_str(String *str,String *save_str) } +/* + For the moment, UDF functions are returning DECIMAL values as strings +*/ + my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) { char buf[DECIMAL_MAX_STR_LENGTH+1], *end; @@ -2609,8 +2625,8 @@ my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) *null_value= 1; return 0; } - buf[res_length]= 0; - str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end); + end= res+ res_length; + str2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf, &end); return dec_buf; } @@ -2664,9 +2680,9 @@ String *Item_func_udf_int::val_str(String *str) longlong Item_func_udf_decimal::val_int() { my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + longlong result; if (null_value) return 0; - longlong result; my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); return result; } @@ -2675,9 +2691,9 @@ longlong Item_func_udf_decimal::val_int() double Item_func_udf_decimal::val_real() { my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + double result; if (null_value) return 0.0; - double result; my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); return result; } diff --git a/sql/item_func.h b/sql/item_func.h index 20f70fce575..d41ea184769 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -357,18 +357,15 @@ public: }; -class Item_func_int_div :public Item_func +class Item_func_int_div :public Item_int_func { public: - Item_func_int_div(Item *a,Item *b) :Item_func(a,b) + Item_func_int_div(Item *a,Item *b) :Item_int_func(a,b) {} - double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } longlong val_int(); - String *val_str(String*str); const char *func_name() const { return "DIV"; } void fix_length_and_dec(); void print(String *str) { print_op(str); } - enum Item_result result_type () const { return INT_RESULT; } }; @@ -384,23 +381,15 @@ public: }; -class Item_func_signproc :public Item_func_num1 +class Item_func_neg :public Item_func_num1 { public: - Item_func_signproc(Item *a) :Item_func_num1(a) {} - Item_func_signproc(Item *a, Item *b) :Item_func_num1(a, b) {} - void fix_length_and_dec(); -}; - - -class Item_func_neg :public Item_func_signproc -{ -public: - Item_func_neg(Item *a) :Item_func_signproc(a) {} + Item_func_neg(Item *a) :Item_func_num1(a) {} double real_op(); longlong int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "-"; } + void fix_length_and_dec(); void fix_num_length_and_dec(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 091de8e3a01..9f2da0f7fa1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -47,19 +47,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, fname); } -uint nr_of_decimals(const char *str) -{ - if (strchr(str,'e') || strchr(str,'E')) - return NOT_FIXED_DEC; - if ((str=strchr(str,'.'))) - { - const char *start= ++str; - for (; my_isdigit(system_charset_info,*str) ; str++) ; - return (uint) (str-start); - } - return 0; -} - double Item_str_func::val_real() { diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2ecc1eb083c..b8da1423871 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -125,15 +125,6 @@ Item *Item_sum::get_tmp_table_item(THD *thd) } -my_decimal *Item_sum::val_decimal(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed); - DBUG_ASSERT(decimal_value); - int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); - return decimal_value; -} - - bool Item_sum::walk (Item_processor processor, byte *argument) { if (arg_count) @@ -178,38 +169,26 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, String * Item_sum_num::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); - return str; + return val_string_from_real(str); } my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; - double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); - return (decimal_value); + return val_decimal_from_real(decimal_value); } String * Item_sum_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - longlong nr= val_int(); - if (null_value) - return 0; - if (unsigned_flag) - str->set((ulonglong) nr, &my_charset_bin); - else - str->set(nr, &my_charset_bin); - return str; + return val_string_from_int(str); +} + + +my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value) +{ + return val_decimal_from_int(decimal_value); } @@ -249,8 +228,8 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), used_table_cache(item->used_table_cache), was_values(item->was_values) { - switch (hybrid_type) - { + /* copy results from old value */ + switch (hybrid_type) { case INT_RESULT: sum_int= item->sum_int; break; @@ -288,8 +267,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return TRUE; decimals=item->decimals; - switch (hybrid_type= item->result_type()) - { + switch (hybrid_type= item->result_type()) { case INT_RESULT: max_length= 20; sum_int= 0; @@ -334,6 +312,7 @@ Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) :Item_sum_num(thd, item), hybrid_type(item->hybrid_type), curr_dec_buff(item->curr_dec_buff) { + /* TODO: check if the following assignments are really needed */ if (hybrid_type == DECIMAL_RESULT) { my_decimal2decimal(item->dec_buffs, dec_buffs); @@ -369,8 +348,7 @@ void Item_sum_sum::fix_length_and_dec() DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); maybe_null=null_value=1; decimals= args[0]->decimals; - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -434,7 +412,7 @@ longlong Item_sum_sum::val_int() &result); return result; } - return Item_sum_num::val_int(); + return (longlong) val_real(); } @@ -447,28 +425,22 @@ double Item_sum_sum::val_real() } -String *Item_sum_sum::val_str(String*str) +String *Item_sum_sum::val_str(String *str) { if (hybrid_type == DECIMAL_RESULT) - { - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, decimals, - FALSE, dec_buffs + curr_dec_buff); - my_decimal2string(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, - 0, 0, 0, str); - return str; - } - return Item_sum_num::val_str(str); + return val_string_from_decimal(str); + return val_string_from_real(str); } my_decimal *Item_sum_sum::val_decimal(my_decimal *val) { - DBUG_ASSERT(hybrid_type == DECIMAL_RESULT); - return(dec_buffs + curr_dec_buff); + if (hybrid_type == DECIMAL_RESULT) + return (dec_buffs + curr_dec_buff); + return val_decimal_from_real(val); } + /* Item_sum_sum_distinct */ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) @@ -519,6 +491,7 @@ static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) C_MODE_END + bool Item_sum_sum_distinct::setup(THD *thd) { DBUG_ENTER("Item_sum_sum_distinct::setup"); @@ -539,15 +512,20 @@ bool Item_sum_sum_distinct::setup(THD *thd) TODO: if underlying item result fits in 4 bytes we can take advantage of it and have tree of long/ulong. It gives 10% performance boost */ - uint *key_length_ptr= (uint *)thd->alloc(sizeof(uint)); - *key_length_ptr= ((hybrid_type == DECIMAL_RESULT) ? - my_decimal_get_binary_size(args[0]->max_length, - args[0]->decimals) : - sizeof(double)); - tree= new Unique(simple_raw_key_cmp, key_length_ptr, *key_length_ptr, + + /* + It's safe to use key_length here as even if we do copy_or_same() + the new item will just share the old items key_length, which will not + change or disappear during the life time of this item. + */ + key_length= ((hybrid_type == DECIMAL_RESULT) ? + my_decimal_get_binary_size(args[0]->max_length, + args[0]->decimals) : + sizeof(double)); + tree= new Unique(simple_raw_key_cmp, &key_length, key_length, thd->variables.max_heap_table_size); DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, - *key_length_ptr)); + key_length)); DBUG_RETURN(tree == 0); } @@ -640,6 +618,7 @@ static int sum_sum_distinct_decimal(void *element, element_count num_of_dups, C_MODE_END + double Item_sum_sum_distinct::val_real() { DBUG_ENTER("Item_sum_sum_distinct::val"); @@ -685,17 +664,17 @@ my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake) longlong Item_sum_sum_distinct::val_int() { - longlong i; + longlong result; if (hybrid_type == DECIMAL_RESULT) { /* Item_sum_sum_distinct::val_decimal do not use argument */ my_decimal *val= val_decimal(0); if (!null_value) - my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &i); + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); } else - i= (longlong) val_real(); - return i; + result= (longlong) val_real(); + return result; } @@ -703,22 +682,8 @@ String *Item_sum_sum_distinct::val_str(String *str) { DBUG_ASSERT(fixed == 1); if (hybrid_type == DECIMAL_RESULT) - { - /* Item_sum_sum_distinct::val_decimal do not use argument */ - my_decimal *val= val_decimal(0); - if (null_value) - return 0; - my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); - my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); - } - else - { - double nr= val_real(); - if (null_value) - return 0; - str->set(nr, decimals, &my_charset_bin); - } - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } @@ -792,23 +757,21 @@ Item *Item_sum_avg::copy_or_same(THD* thd) Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { + if (group) + { + /* + We must store both value and counter in the temporary table in one field. + The easyest way is to do this is to store both value in a string + and unpack on access. + */ + return new Field_string(((hybrid_type == DECIMAL_RESULT) ? + dec_bin_size : sizeof(double)) + sizeof(longlong), + 0, name, table, &my_charset_bin); + } if (hybrid_type == DECIMAL_RESULT) - { - if (group) - return new Field_string(dec_bin_size + sizeof(longlong), - 0, name, table, &my_charset_bin); - else - return new Field_new_decimal(f_precision, - maybe_null, name, table, f_scale); - } - else - { - if (group) - return new Field_string(sizeof(double)+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_double(max_length, maybe_null, name, table, decimals); - } + return new Field_new_decimal(f_precision, + maybe_null, name, table, f_scale); + return new Field_double(max_length, maybe_null, name, table, decimals); } @@ -842,14 +805,15 @@ double Item_sum_avg::val_real() my_decimal *Item_sum_avg::val_decimal(my_decimal *val) { + my_decimal sum, cnt; + const my_decimal *sum_dec; DBUG_ASSERT(fixed == 1); if (!count) { null_value=1; return NULL; } - my_decimal sum, cnt; - const my_decimal *sum_dec= Item_sum_sum::val_decimal(&sum); + sum_dec= Item_sum_sum::val_decimal(&sum); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); return val; @@ -859,23 +823,11 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) String *Item_sum_avg::val_str(String *str) { if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); - my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); - return str; - } - double nr= val_real(); - if (null_value) - return NULL; - str->set(nr, decimals, &my_charset_bin); - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } - /* Standard deviation */ @@ -922,11 +874,10 @@ Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): void Item_sum_variance::fix_length_and_dec() { - DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); - maybe_null=null_value=1; + DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); + maybe_null= null_value= 1; decimals= args[0]->decimals + 4; - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -934,12 +885,21 @@ void Item_sum_variance::fix_length_and_dec() break; case INT_RESULT: case DECIMAL_RESULT: - /* SUM result can't be longer than length(arg)*2 + digits_after_the_point_to_add*/ + /* + SUM result can't be longer than length(arg)*2 + + digits_after_the_point_to_add + */ max_length= args[0]->max_length*2 + 4; cur_dec= 0; hybrid_type= DECIMAL_RESULT; my_decimal_set_zero(dec_sum); my_decimal_set_zero(dec_sqr); + + /* + The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2 + becasue we need to be able to calculate in dec_bin_size1 + column_value * column_value + */ f_scale0= args[0]->decimals; f_precision0= DECIMAL_MAX_LENGTH / 2; f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); @@ -971,23 +931,22 @@ Item *Item_sum_variance::copy_or_same(THD* thd) Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { + if (group) + { + /* + We must store both value and counter in the temporary table in one field. + The easyest way is to do this is to store both value in a string + and unpack on access. + */ + return new Field_string(((hybrid_type == DECIMAL_RESULT) ? + dec_bin_size0 + dec_bin_size1 : + sizeof(double)*2) + sizeof(longlong), + 0, name, table, &my_charset_bin); + } if (hybrid_type == DECIMAL_RESULT) - { - if (group) - return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_new_decimal(DECIMAL_MAX_LENGTH, - maybe_null, name, table, f_scale1 + 4); - } - else - { - if (group) - return new Field_string(sizeof(double)*2+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_double(max_length, maybe_null,name,table,decimals); - } + return new Field_new_decimal(DECIMAL_MAX_LENGTH, + maybe_null, name, table, f_scale1 + 4); + return new Field_double(max_length, maybe_null,name,table,decimals); } @@ -1038,19 +997,15 @@ bool Item_sum_variance::add() double Item_sum_variance::val_real() { DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + return val_real_from_decimal(); + if (!count) { null_value=1; return 0.0; } null_value=0; - if (hybrid_type == DECIMAL_RESULT) - { - double result; - my_decimal dec_buf, *dec= Item_sum_variance::val_decimal(&dec_buf); - my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); - return result; - } /* Avoid problems when the precision isn't good enough */ double tmp=ulonglong2double(count); double tmp2=(sum_sqr - sum*sum/tmp)/tmp; @@ -1060,22 +1015,17 @@ double Item_sum_variance::val_real() my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) { + my_decimal count_buf, sum_sqr_buf; DBUG_ASSERT(fixed ==1 ); if (hybrid_type == REAL_RESULT) - { - double result= Item_sum_variance::val_real(); - if (null_value) - return 0; - double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf); - return dec_buf; - } + return val_decimal_from_real(dec_buf); + if (!count) { null_value= 1; return 0; } null_value= 0; - my_decimal count_buf, sum_sqr_buf; int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf); my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sum+cur_dec, dec_sum+cur_dec); @@ -1085,49 +1035,53 @@ my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) return dec_buf; } + void Item_sum_variance::reset_field() { - char *res=result_field->ptr; + double nr; + char *res= result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) { - my_decimal value, *arg_dec= args[0]->val_decimal(&value); + my_decimal value, *arg_dec, *arg2_dec; + longlong tmp; + + arg_dec= args[0]->val_decimal(&value); if (args[0]->null_value) { - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res, f_precision0, f_scale0); - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - longlong tmp=0; - int8store(res,tmp); + arg_dec= arg2_dec= &decimal_zero; + tmp= 0; } else { - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, - res, f_precision0, f_scale0); my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec); - my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - longlong tmp=1; - int8store(res,tmp); + arg2_dec= dec_sum; + tmp= 1; } + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, + res, f_precision0, f_scale0); + my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + int8store(res,tmp); return; } - double nr= args[0]->val_real(); + nr= args[0]->val_real(); if (args[0]->null_value) bzero(res,sizeof(double)*2+sizeof(longlong)); else { + longlong tmp; float8store(res,nr); nr*=nr; float8store(res+sizeof(double),nr); - longlong tmp=1; + tmp= 1; int8store(res+sizeof(double)*2,tmp); } } + void Item_sum_variance::update_field() { longlong field_count; @@ -1170,15 +1124,16 @@ void Item_sum_variance::update_field() } float8store(res,old_nr); float8store(res+sizeof(double),old_sqr); - int8store(res+sizeof(double)*2,field_count); + res+= sizeof(double)*2; + int8store(res,field_count); } + /* min & max */ void Item_sum_hybrid::clear() { - switch (hybrid_type) - { + switch (hybrid_type) { case INT_RESULT: sum_int= 0; break; @@ -1231,8 +1186,7 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) - { + switch (hybrid_type) { case INT_RESULT: return sum_int; case DECIMAL_RESULT: @@ -1539,8 +1493,7 @@ void Item_sum_num::reset_field() void Item_sum_hybrid::reset_field() { - switch(hybrid_type) - { + switch(hybrid_type) { case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; @@ -1604,8 +1557,13 @@ void Item_sum_hybrid::reset_field() else result_field->set_notnull(); } - if (!args[0]->null_value) - result_field->store_decimal(arg_dec); + /* + We must store zero in the field as we will use the field value in + add() + */ + if (!arg_dec) // Null + arg_dec= &decimal_zero; + result_field->store_decimal(arg_dec); break; } case ROW_RESULT: @@ -1620,10 +1578,9 @@ void Item_sum_sum::reset_field() if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); - if (args[0]->null_value) - result_field->reset(); - else - result_field->store_decimal(arg_val); + if (!arg_val) // Null + arg_val= &decimal_zero; + result_field->store_decimal(arg_val); } else { @@ -1660,23 +1617,18 @@ void Item_sum_avg::reset_field() char *res=result_field->ptr; if (hybrid_type == DECIMAL_RESULT) { + longlong tmp; my_decimal value, *arg_dec= args[0]->val_decimal(&value); if (args[0]->null_value) { - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res, f_precision, f_scale); - res+= dec_bin_size; - longlong tmp=0; - int8store(res,tmp); + arg_dec= &decimal_zero; + tmp= 0; } else - { - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, - res, f_precision, f_scale); - res+= dec_bin_size; - longlong tmp=1; - int8store(res,tmp); - } + tmp= 1; + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale); + res+= dec_bin_size; + int8store(res, tmp); } else { @@ -1686,14 +1638,15 @@ void Item_sum_avg::reset_field() bzero(res,sizeof(double)+sizeof(longlong)); else { + longlong tmp= 1; float8store(res,nr); res+=sizeof(double); - longlong tmp=1; int8store(res,tmp); } } } + void Item_sum_bit::reset_field() { reset(); @@ -1708,6 +1661,7 @@ void Item_sum_bit::update_field() int8store(res, bits); } + /* ** calc next value and merge it with field_value */ @@ -1781,36 +1735,36 @@ void Item_sum_avg::update_field() dec_buffs + 1, f_precision, f_scale); field_count= sint8korr(res + dec_bin_size); my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1); - field_count++; my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs, res, f_precision, f_scale); res+= dec_bin_size; + field_count++; int8store(res, field_count); } } else { - double nr, old_nr; - - float8get(old_nr, res); - field_count= sint8korr(res + sizeof(double)); + double nr; nr= args[0]->val_real(); if (!args[0]->null_value) { + double old_nr; + float8get(old_nr, res); + field_count= sint8korr(res + sizeof(double)); old_nr+= nr; + float8store(res,old_nr); + res+= sizeof(double); field_count++; + int8store(res, field_count); } - float8store(res,old_nr); - res+= sizeof(double); - int8store(res, field_count); } } + void Item_sum_hybrid::update_field() { - switch (hybrid_type) - { + switch (hybrid_type) { case STRING_RESULT: min_max_update_str_field(); break; @@ -1938,52 +1892,45 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item) double Item_avg_field::val_real() { // fix_fields() never calls for this Item - if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return 0.0; - double d; - my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); - return d; - } - else - { - double nr; - longlong count; - float8get(nr,field->ptr); - char *res=(field->ptr+sizeof(double)); - count=sint8korr(res); + double nr; + longlong count; + char *res; - if (!count) - { - null_value=1; - return 0.0; - } - null_value=0; - return nr/(double) count; - } + if (hybrid_type == DECIMAL_RESULT) + return val_real_from_decimal(); + + float8get(nr,field->ptr); + res= (field->ptr+sizeof(double)); + count= sint8korr(res); + + if ((null_value= !count)) + return 0.0; + return nr/(double) count; } + longlong Item_avg_field::val_int() { - return (longlong)val_real(); + return (longlong) val_real(); } -my_decimal *Item_avg_field::val_decimal(my_decimal * val) +my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf) { // fix_fields() never calls for this Item + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + longlong count= sint8korr(field->ptr + dec_bin_size); if ((null_value= !count)) - return NULL; + return 0; my_decimal dec_count, dec_field; binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr, &dec_field, f_precision, f_scale); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); - my_decimal_div(E_DEC_FATAL_ERROR, val, &dec_field, &dec_count, 4); - return val; + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4); + return dec_buf; } @@ -1991,35 +1938,64 @@ String *Item_avg_field::val_str(String *str) { // fix_fields() never calls for this Item if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); - my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); - } - else - { - double nr= Item_avg_field::val_real(); - if (null_value) - return 0; - str->set(nr, decimals, &my_charset_bin); - } - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } + Item_std_field::Item_std_field(Item_sum_std *item) : Item_variance_field(item) { } + double Item_std_field::val_real() { + double nr; // fix_fields() never calls for this Item - double tmp= Item_variance_field::val_real(); - return tmp <= 0.0 ? 0.0 : sqrt(tmp); + if (hybrid_type == REAL_RESULT) + { + /* + We can't call Item_variance_field::val_real() on a DECIMAL_RESULT + as this would call Item_std_field::val_decimal() and we would + calculate sqrt() twice + */ + nr= Item_variance_field::val_real(); + } + else + { + my_decimal dec_buf,*dec; + dec= Item_variance_field::val_decimal(&dec_buf); + if (!dec) + nr= 0.0; // NULL; Return 0.0 + else + my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); + } + return nr <= 0.0 ? 0.0 : sqrt(nr); } + +my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf) +{ + /* + We can't call val_decimal_from_real() for DECIMAL_RESULT as + Item_variance_field::val_real() would cause an infinite loop + */ + my_decimal tmp_dec, *dec; + double nr; + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + dec= Item_variance_field::val_decimal(dec_buf); + if (!dec) + return 0; + my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); + nr= nr <= 0.0 ? 0.0 : sqrt(nr); + double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec); + my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf); + return dec_buf; +} + + Item_variance_field::Item_variance_field(Item_sum_variance *item) { name=item->name; @@ -2038,49 +2014,42 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item) } } + double Item_variance_field::val_real() { // fix_fields() never calls for this Item if (hybrid_type == DECIMAL_RESULT) - { - my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); - if (null_value) - return 0.0; - double d; - my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); - return d; - } + return val_real_from_decimal(); + double sum,sum_sqr; longlong count; float8get(sum,field->ptr); float8get(sum_sqr,(field->ptr+sizeof(double))); count=sint8korr(field->ptr+sizeof(double)*2); - if (!count) - { - null_value=1; + if ((null_value= !count)) return 0.0; - } - null_value=0; + double tmp= (double) count; double tmp2=(sum_sqr - sum*sum/tmp)/tmp; return tmp2 <= 0.0 ? 0.0 : tmp2; } + String *Item_variance_field::val_str(String *str) { - // fix_fields() never calls for this Item - double nr= val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); - return str; + if (hybrid_type == DECIMAL_RESULT) + return val_string_from_decimal(str); + return val_string_from_real(str); } my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) { // fix_fields() never calls for this Item + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1); if ((null_value= !count)) return 0; @@ -2478,55 +2447,34 @@ double Item_sum_udf_float::val_real() DBUG_RETURN(udf.val(&null_value)); } + String *Item_sum_udf_float::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; /* purecov: inspected */ - str->set(nr,decimals, &my_charset_bin); - return str; + return val_string_from_real(str); } -Item *Item_sum_udf_int::copy_or_same(THD* thd) +my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec) { - return new (thd->mem_root) Item_sum_udf_int(thd, this); + return val_decimal_from_real(dec); } String *Item_sum_udf_decimal::val_str(String *str) { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); - if (null_value) - return 0; - if (str->length() < DECIMAL_MAX_STR_LENGTH) - str->length(DECIMAL_MAX_STR_LENGTH); - my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); - my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str); - return str; + return val_string_from_decimal(str); } double Item_sum_udf_decimal::val_real() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); - if (null_value) - return 0.0; - double result; - my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); - return result; + return val_real_from_decimal(); } longlong Item_sum_udf_decimal::val_int() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); - if (null_value) - return 0; - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); - return result; + return val_int_from_decimal(); } @@ -2547,6 +2495,11 @@ Item *Item_sum_udf_decimal::copy_or_same(THD* thd) } +Item *Item_sum_udf_int::copy_or_same(THD* thd) +{ + return new (thd->mem_root) Item_sum_udf_int(thd, this); +} + longlong Item_sum_udf_int::val_int() { DBUG_ASSERT(fixed == 1); @@ -2559,14 +2512,15 @@ longlong Item_sum_udf_int::val_int() String *Item_sum_udf_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - longlong nr=val_int(); - if (null_value) - return 0; - str->set(nr, &my_charset_bin); - return str; + return val_string_from_int(str); } +my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec) +{ + return val_decimal_from_int(dec); +} + + /* Default max_length is max argument length */ void Item_sum_udf_str::fix_length_and_dec() @@ -2585,6 +2539,11 @@ Item *Item_sum_udf_str::copy_or_same(THD* thd) } +my_decimal *Item_sum_udf_str::val_decimal(my_decimal *dec) +{ + return val_decimal_from_string(dec); +} + String *Item_sum_udf_str::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_sum.h b/sql/item_sum.h index d759f5607c3..e284416f0f5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -78,7 +78,6 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - my_decimal *val_decimal(my_decimal *); virtual const char *func_name() const { return "?"; } virtual Item *result_item(Field *field) { return new Item_field(field);} @@ -93,7 +92,6 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); - virtual int scale() { return decimals; } virtual Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); @@ -129,6 +127,7 @@ public: Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; maybe_null=null_value=0; } @@ -176,6 +175,7 @@ class Item_sum_sum_distinct :public Item_sum_sum Unique *tree; byte *dec_bin_buff; my_decimal tmp_dec; + uint key_length; private: Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); public: @@ -451,7 +451,9 @@ public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } double val_real(); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; /* @@ -472,6 +474,7 @@ class Item_sum_std :public Item_sum_variance const char *func_name() const { return "std"; } Item *copy_or_same(THD* thd); enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; // This class is a string or number function depending on num_func @@ -650,6 +653,7 @@ class Item_sum_udf_float :public Item_udf_sum } double val_real(); String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec() { fix_num_length_and_dec(); } Item *copy_or_same(THD* thd); }; @@ -667,6 +671,7 @@ public: double val_real() { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } Item *copy_or_same(THD* thd); @@ -697,11 +702,13 @@ public: return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err_not_used) : (longlong) 0; } + my_decimal *val_decimal(my_decimal *dec); enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); Item *copy_or_same(THD* thd); }; + class Item_sum_udf_decimal :public Item_udf_sum { public: @@ -864,6 +871,10 @@ class Item_func_group_concat : public Item_sum end_ptr= (char*) res->ptr()+ res->length(); return my_strtoll10(res->ptr(), &end_ptr, &error); } + my_decimal *val_decimal(my_decimal *decimal_value) + { + return val_decimal_from_string(decimal_value); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} diff --git a/sql/log_event.cc b/sql/log_event.cc index d2a0e8642f9..d760445e493 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3281,7 +3281,7 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las bin2decimal(val+2, &dec, precision, scale); decimal2string(&dec, str_buf, &str_len, 0, 0, 0); str_buf[str_len]= 0; - fprintf(file, "%s",str_buf); + fprintf(file, ":=%s;\n",str_buf); break; } case STRING_RESULT: diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index f028b1fa1a1..94b473a8c36 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -13,6 +13,7 @@ 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 "mysql_priv.h" #ifndef MYSQL_CLIENT @@ -154,10 +155,11 @@ int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, E_DEC_BAD_NUM E_DEC_OOM */ + int str2my_decimal(uint mask, const char *from, uint length, CHARSET_INFO *charset, my_decimal *decimal_value) { - char *end; + char *end, *from_end; int err; char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff, sizeof(buff), &my_charset_bin); @@ -169,10 +171,20 @@ int str2my_decimal(uint mask, const char *from, uint length, length= tmp.length(); charset= &my_charset_bin; } - my_decimal_set_zero(decimal_value); + from_end= end= (char*) from+length; err= string2decimal((char *)from, (decimal *)decimal_value, &end); - if ((uint) (end-from) != length && !err) - err= E_DEC_TRUNCATED; + if (end != from_end && !err) + { + /* Give warining if there is something other than end space */ + for ( ; end < from_end; end++) + { + if (!my_isspace(&my_charset_latin1, *end)) + { + err= E_DEC_TRUNCATED; + break; + } + } + } check_result(mask, err); return err; } @@ -200,12 +212,25 @@ print_decimal_buff(const my_decimal *dec, const byte* ptr, int length) { print_decimal(dec); fprintf(DBUG_FILE, "Record: "); - for(int i= 0; i < length; i++) + for (int i= 0; i < length; i++) { fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]); } fprintf(DBUG_FILE, "\n"); } + + +void dbug_print_decimal(const char *tag, const char *format, my_decimal *val) +{ + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + if (!val) + str.set("NULL", 4, &my_charset_bin); + else + my_decimal2string(0, val, 0, 0, 0, &str); + DBUG_PRINT(tag, (format, val)); +} + #endif diff --git a/sql/my_decimal.h b/sql/my_decimal.h index 63d3fb7e2e5..728ac48ce4f 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -68,10 +68,13 @@ inline uint my_decimal_size(uint precision, uint scale) } -/* my_decimal class limits 'decimal' type to what we need in MySQL */ -/* It internally all necessary space iside the instance so no extra */ -/* memory is needed. One should call fix_buffer_pointer() function */ -/* when he moves my_decimal objects in memory */ +/* + my_decimal class limits 'decimal' type to what we need in MySQL + It contains internally all necessary space needed by the instance so + no extra memory is needed. One should call fix_buffer_pointer() function + when he moves my_decimal objects in memory +*/ + class my_decimal :public decimal { decimal_digit buffer[DECIMAL_BUFF_LENGTH]; @@ -83,6 +86,7 @@ public: len= DECIMAL_BUFF_LENGTH; buf= buffer; #if !defined(HAVE_purify) && !defined(DBUG_OFF) + /* Set buffer to 'random' value to find wrong buffer usage */ for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) buffer[i]= i; #endif @@ -101,6 +105,9 @@ public: #ifndef DBUG_OFF void print_decimal(const my_decimal *dec); void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); +void dbug_print_decimal(const char *tag, const char *format, my_decimal *val); +#else +#define dbug_print_decimal(A,B,C) #endif #ifndef MYSQL_CLIENT @@ -158,7 +165,7 @@ inline int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec, int scale) { - return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec, + return check_result(mask, bin2decimal((char *)bin, (decimal*) d, prec, scale)); } @@ -166,7 +173,7 @@ int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec, inline int my_decimal_set_zero(my_decimal *d) { - decimal_make_zero(((decimal *)d)); + decimal_make_zero(((decimal*) d)); return 0; } @@ -174,7 +181,7 @@ int my_decimal_set_zero(my_decimal *d) inline bool my_decimal_is_zero(const my_decimal *decimal_value) { - return decimal_is_zero((decimal *)decimal_value); + return decimal_is_zero((decimal*) decimal_value); } @@ -182,7 +189,7 @@ inline int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, scale, + return check_result(mask, decimal_round((decimal*) from, to, scale, (truncate ? TRUNCATE : HALF_UP))); } @@ -190,14 +197,14 @@ int my_decimal_round(uint mask, const my_decimal *from, int scale, inline int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, 0, FLOOR)); + return check_result(mask, decimal_round((decimal*) from, to, 0, FLOOR)); } inline int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, 0, CEILING)); + return check_result(mask, decimal_round((decimal*) from, to, 0, CEILING)); } @@ -222,17 +229,15 @@ int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, inline int my_decimal2double(uint mask, const my_decimal *d, double *result) { - return check_result(mask, decimal2double((decimal *)d, result)); + /* No need to call check_result as this will always succeed */ + return decimal2double((decimal*) d, result); } inline -int str2my_decimal(uint mask, const char *str, my_decimal *d, - char **end= 0) +int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { - /* set it to 0 to avoid junk in value in case of error of conversion */ - my_decimal_set_zero(d); - return check_result(mask, string2decimal((char *)str, (decimal *)d, end)); + return check_result(mask, string2decimal(str, (decimal*) d, end)); } @@ -252,7 +257,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d) inline int double2my_decimal(uint mask, double val, my_decimal *d) { - return check_result(mask, double2decimal(val, (decimal *)d)); + return check_result(mask, double2decimal(val, (decimal*) d)); } @@ -266,10 +271,9 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) inline -int my_decimal_neg(st_decimal *arg) +void my_decimal_neg(st_decimal *arg) { decimal_neg(arg); - return 0; } @@ -277,7 +281,7 @@ inline int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_add((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_add((decimal*) a, (decimal*) b, res)); } @@ -285,7 +289,7 @@ inline int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_sub((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_sub((decimal*) a, (decimal*) b, res)); } @@ -293,7 +297,7 @@ inline int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mul((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_mul((decimal*) a, (decimal*) b, res)); } @@ -301,7 +305,7 @@ inline int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b, int div_scale_inc) { - return check_result(mask, decimal_div((decimal *)a, (decimal *)b, res, + return check_result(mask, decimal_div((decimal*) a, (decimal*) b, res, div_scale_inc)); } @@ -310,7 +314,7 @@ inline int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mod((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_mod((decimal*) a, (decimal*) b, res)); } @@ -318,14 +322,14 @@ int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { - return decimal_cmp((decimal *)a, (decimal *)b); + return decimal_cmp((decimal*) a, (decimal*) b); } inline void max_my_decimal(my_decimal *to, int precision, int frac) { DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH); - max_decimal(precision, frac, (decimal *)to); + max_decimal(precision, frac, (decimal*) to); } #endif /*my_decimal_h*/ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fdcf061ab7a..4f8d31771aa 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -400,8 +400,6 @@ typedef struct st_sql_list { } SQL_LIST; -uint nr_of_decimals(const char *str); /* Neaded by sql_string.h */ - extern pthread_key(THD*, THR_THD); inline THD *_current_thd(void) { diff --git a/sql/protocol.cc b/sql/protocol.cc index 7c56bb3fc7a..657341b8bdc 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -822,15 +822,9 @@ bool Protocol_simple::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - int buf_size= my_decimal_string_length(d); - char *buff= (char *)my_alloca(buf_size); - String str(buff, buf_size, &my_charset_bin); - if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) - { - my_afree(buff); - return TRUE; - } - my_afree(buff); + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); return net_store_data(str.ptr(), str.length()); } @@ -1056,15 +1050,9 @@ bool Protocol_prep::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - int buf_size= my_decimal_string_length(d); - char *buff= (char *)my_alloca(buf_size); - String str(buff, buf_size, &my_charset_bin); - if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) - { - my_afree(buff); - return TRUE; - } - my_afree(buff); + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); return store(str.ptr(), str.length(), str.charset()); } diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc index a5bf94469e7..5ac03c4d427 100644 --- a/sql/protocol_cursor.cc +++ b/sql/protocol_cursor.cc @@ -104,15 +104,15 @@ bool Protocol_cursor::write() byte *to; new_record= (MYSQL_ROWS *)alloc_root(alloc, - sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length()); + sizeof(MYSQL_ROWS) + (field_count + 2)*sizeof(char *) + packet->length()); if (!new_record) goto err; data_tmp= (byte **)(new_record + 1); new_record->data= (char **)data_tmp; - to= (byte *)data_tmp + (field_count + 1)*sizeof(char *); + to= (byte *)data_tmp + (field_count + 2)*sizeof(char *); - for (; cur_field < fields_end; ++cur_field, ++data_tmp) + for (; cur_field < fields_end; cur_field++, data_tmp++) { if ((len= net_field_length((uchar **)&cp)) == 0 || len == NULL_LENGTH) @@ -135,7 +135,8 @@ bool Protocol_cursor::write() cur_field->max_length=len; } } - *data_tmp= 0; + data_tmp[0]= to; // Pointer to last used byte + data_tmp[1]= 0; *prev_record= new_record; prev_record= &new_record->next; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 075aef9d286..72b6fb599be 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -158,69 +158,12 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } case DECIMAL_RESULT: { - switch (it->result_type()) - { - case DECIMAL_RESULT: - { - my_decimal value, *val= it->val_decimal(&value); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val); - break; - } - case INT_RESULT: - { - longlong val= it->val_int(); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val, (int)it->max_length, - (bool)it->unsigned_flag); - break; - } - case REAL_RESULT: - { - double val= it->val_real(); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val, (int)it->max_length, - (int)it->decimals); - break; - } - case STRING_RESULT: - { - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer, sizeof(buffer), it->collation.collation); - String *val= it->val_str(&tmp); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val->ptr(), val->length(), val->charset()); - break; - } - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } -#ifndef DBUG_OFF + my_decimal value, *val= it->val_decimal(&value); if (it->null_value) - { - DBUG_PRINT("info", ("DECIMAL_RESULT: null")); - } + it= new Item_null(); else - { - my_decimal value, *val= it->val_decimal(&value); - int len; - char *buff= - (char *)my_alloca(len= my_decimal_string_length(val) + 3); - String str(buff, len, &my_charset_bin); - my_decimal2string(0, val, 0, 0, 0, &str); - DBUG_PRINT("info", ("DECIMAL_RESULT: %s", str.ptr())); - my_afree(buff); - } -#endif + it= new Item_decimal(val); + dbug_print_decimal("info", "DECIMAL_RESULT: %s", val); break; } case STRING_RESULT: @@ -236,8 +179,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } else { - DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick())); - it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()), + DBUG_PRINT("info",("default result: %*s", + s->length(), s->c_ptr_quick())); + it= new Item_string(thd->strmake(s->ptr(), s->length()), s->length(), it->collation.collation); } break; @@ -811,7 +755,7 @@ sp_head::execute_procedure(THD *thd, List *args) suv= new Item_func_set_user_var(guv->get_name(), item); /* - we do not check suv->fixed, bacause it can't be fixed after + we do not check suv->fixed, because it can't be fixed after creation */ suv->fix_fields(thd, NULL, &item); diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 0c6c8c5aa70..5b177650726 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -243,27 +243,36 @@ sp_cursor::fetch(THD *thd, List *vars) if (!s) it= new Item_null(); else - switch (sp_map_result_type(pv->type)) - { + { + /* + Length of data can be calculated as: + pointer_to_next_not_null_object - s -1 + where the last -1 is to remove the end \0 + */ + uint len; + MYSQL_ROW next= row+fldcount+1; + while (!*next) // Skip nulls + next++; + len= (*next -s)-1; + switch (sp_map_result_type(pv->type)) { case INT_RESULT: it= new Item_int(s); break; case REAL_RESULT: - it= new Item_float(s, strlen(s)); + it= new Item_float(s, len); break; case DECIMAL_RESULT: - it= new Item_decimal(s, strlen(s), thd->db_charset); + it= new Item_decimal(s, len, thd->db_charset); break; case STRING_RESULT: - { - uint len= strlen(s); - it= new Item_string(thd->strmake(s, len), len, thd->db_charset); - break; - } + /* TODO: Document why we do an extra copy of the string 's' here */ + it= new Item_string(thd->strmake(s, len), len, thd->db_charset); + break; case ROW_RESULT: default: DBUG_ASSERT(0); } + } thd->spcont->set_item(pv->offset, it); } if (fldcount < m_prot->get_field_count()) diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index c2eea524cac..642de13039e 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -133,22 +133,30 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, Item *item; while ((item = it++)) { - if (item->result_type() == INT_RESULT) - { + field_info *new_field; + switch (item->result_type()) { + case INT_RESULT: // Check if fieldtype is ulonglong if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG && ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag) - *f_info++ = new field_ulonglong(item, pc); + new_field= new field_ulonglong(item, pc); else - *f_info++ = new field_longlong(item, pc); + new_field= new field_longlong(item, pc); + break; + case REAL_RESULT: + new_field= new field_real(item, pc); + break; + case DECIMAL_RESULT: + new_field= new field_decimal(item, pc); + break; + case STRING_RESULT: + new_field= new field_str(item, pc); + break; + default: + goto err; } - if (item->result_type() == REAL_RESULT) - *f_info++ = new field_real(item, pc); - if (item->result_type() == DECIMAL_RESULT) - *f_info++= new field_decimal(item, pc); - if (item->result_type() == STRING_RESULT) - *f_info++ = new field_str(item, pc); + *f_info++= new_field; } } DBUG_RETURN(pc); @@ -470,6 +478,9 @@ void field_decimal::add() length= my_decimal_string_length(dec); + if (decimal_is_zero(dec)) + empty++; + if (room_in_tree) { char buf[DECIMAL_MAX_FIELD_SIZE]; @@ -502,7 +513,7 @@ void field_decimal::add() cur_sum= 0; min_length = max_length = length; } - else + else if (!decimal_is_zero(dec)) { int next_cur_sum= cur_sum ^ 1; my_decimal sqr_buf; @@ -972,15 +983,17 @@ void field_decimal::get_opt_type(String *answer, { my_decimal zero; char buff[MAX_FIELD_WIDTH]; + uint length; my_decimal_set_zero(&zero); my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0); - sprintf(buff, "DECIMAL(%d, %d)", - (int)(max_length - (item->decimals ? 1 : 0)), item->decimals); + length= my_sprintf(buff, (buff, "DECIMAL(%d, %d)", + (int) (max_length - (item->decimals ? 1 : 0)), + item->decimals)); if (is_unsigned) - strcat(buff, " UNSIGNED"); - answer->append(buff, (uint) strlen(buff)); + length= (uint) (strmov(buff+length, " UNSIGNED")- buff); + answer->append(buff, length); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index eef86921012..34d6782ab52 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3400,8 +3400,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if (!(*conds)->fixed && - (*conds)->fix_fields(thd, tables, conds)) + if ((*conds)->fix_fields(thd, tables, conds)) goto err_no_arena; } } @@ -3413,8 +3412,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr)) + if (embedded->on_expr->fix_fields(thd, tables, + &embedded->on_expr)) goto err_no_arena; } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0dae2d37062..cebec316af9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1366,10 +1366,9 @@ bool select_max_min_finder_subselect::cmp_real() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && val1 > val2); - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - val1 < val2); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); } bool select_max_min_finder_subselect::cmp_int() @@ -1380,30 +1379,23 @@ bool select_max_min_finder_subselect::cmp_int() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && val1 > val2); - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - val1 < val2); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); } bool select_max_min_finder_subselect::cmp_decimal() { - String *val1, *val2, buf1, buf2; Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); - /* - as far as both operand is Item_cache buf1 & buf2 will not be used, - but added for safety - */ my_decimal cval, *cvalue= cache->val_decimal(&cval); my_decimal mval, *mvalue= maxmin->val_decimal(&mval); if (fmax) return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && my_decimal_cmp(cvalue, mvalue) > 0) ; - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - my_decimal_cmp(cvalue,mvalue) < 0); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + my_decimal_cmp(cvalue,mvalue) < 0); } bool select_max_min_finder_subselect::cmp_str() @@ -1420,10 +1412,9 @@ bool select_max_min_finder_subselect::cmp_str() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && sortcmp(val1, val2, cache->collation.collation) > 0) ; - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - sortcmp(val1, val2, cache->collation.collation) < 0); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + sortcmp(val1, val2, cache->collation.collation) < 0); } bool select_exists_subselect::send_data(List &items) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index dead6a6e08e..91ced987f6a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7217,8 +7217,9 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) if (conds) { conds= and_conds(conds, table->on_expr); - if (!conds->fixed) - conds->fix_fields(join->thd, 0, &conds); + /* conds is always a new item as both cond and on_expr existed */ + DBUG_ASSERT(!conds->fixed); + conds->fix_fields(join->thd, 0, &conds); } else conds= table->on_expr; diff --git a/strings/decimal.c b/strings/decimal.c index 16c80158722..212bd7204f6 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -743,12 +743,12 @@ int decimal_shift(decimal *dec, int shift) Convert string to decimal SYNOPSIS - str2decl() - from - value to convert + internal_str2decl() + from - value to convert. Doesn't have to be \0 terminated! to - decimal where where the result will be stored to->buf and to->len must be set. - end - if not NULL, *end will be set to the char where - conversion ended + end - Pointer to pointer to end of string. Will on return be + set to the char after the last used character fixed - use to->intg, to->frac as limits for input number NOTE @@ -757,31 +757,36 @@ int decimal_shift(decimal *dec, int shift) RETURN VALUE E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM + In case of E_DEC_FATAL_ERROR *to is set to decimal zero + (to make error handling easier) */ -static int str2dec(char *from, decimal *to, char **end, my_bool fixed) +int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed) { - char *s=from, *s1, *endp; + const char *s= from, *s1, *endp, *end_of_string= *end; int i, intg, frac, error, intg1, frac1; dec1 x,*buf; - LINT_INIT(error); sanity(to); - while (my_isspace(&my_charset_latin1, *s)) + error= E_DEC_BAD_NUM; /* In case of bad number */ + while (s < end_of_string && my_isspace(&my_charset_latin1, *s)) s++; + if (s == end_of_string) + goto fatal_error; + if ((to->sign= (*s == '-'))) s++; else if (*s == '+') s++; s1=s; - while (my_isdigit(&my_charset_latin1, *s)) + while (s < end_of_string && my_isdigit(&my_charset_latin1, *s)) s++; intg=s-s1; - if (*s=='.') + if (s < end_of_string && *s=='.') { endp= s+1; - while (my_isdigit(&my_charset_latin1, *endp)) + while (s < end_of_string && my_isdigit(&my_charset_latin1, *endp)) endp++; frac= endp - s - 1; } @@ -791,12 +796,12 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) endp= s; } - if (end) - *end= endp; + *end= (char*) endp; if (frac+intg == 0) - return E_DEC_BAD_NUM; + goto fatal_error; + error= 0; if (fixed) { if (frac > to->frac) @@ -812,7 +817,10 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) intg1=ROUND_UP(intg); frac1=ROUND_UP(frac); if (intg1+frac1 > to->len) - return E_DEC_OOM; + { + error= E_DEC_OOM; + goto fatal_error; + } } else { @@ -861,36 +869,43 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) } if (i) *buf=x*powers10[DIG_PER_DEC1-i]; - if (*endp == 'e' || *endp == 'E') + + /* Handle exponent */ + if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E')) { - long exp= strtol(endp + 1, &endp, 10); + int str_error; + longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error); - if (end) - *end= endp; - - if (exp > INT_MAX/2) - return E_DEC_OVERFLOW; - if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) - return E_DEC_TRUNCATED; - - if(error != E_DEC_OVERFLOW) - error= decimal_shift(to, exp); + if (end_of_string != endp +1) /* If at least one digit */ + { + *end= (char*) end_of_string; + if (str_error > 0) + { + error= E_DEC_BAD_NUM; + goto fatal_error; + } + if (exp > INT_MAX/2 || (str_error == 0 && exp < 0)) + { + error= E_DEC_OVERFLOW; + goto fatal_error; + } + if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) + { + error= E_DEC_TRUNCATED; + goto fatal_error; + } + if (error != E_DEC_OVERFLOW) + error= decimal_shift(to, (int) exp); + } } + return error; +fatal_error: + decimal_make_zero(to); return error; } -int string2decimal(char *from, decimal *to, char **end) -{ - return str2dec(from, to, end, 0); -} - -int string2decimal_fixed(char *from, decimal *to, char **end) -{ - return str2dec(from, to, end, 1); -} - /* Convert decimal to double @@ -932,9 +947,10 @@ int decimal2double(decimal *from, double *to) int double2decimal(double from, decimal *to) { /* TODO: fix it, when we'll have dtoa */ - char s[400]; + char s[400], *end; sprintf(s, "%f", from); - return string2decimal(s, to, 0); + end= strend(s); + return string2decimal(s, to, &end); } static int ull2dec(ulonglong from, decimal *to) @@ -2160,13 +2176,13 @@ void check_result_code(int actual, int want) { if (actual != want) { - printf("\n^^^^^^^^^^^^^ mast return %d\n", want); + printf("\n^^^^^^^^^^^^^ must return %d\n", want); exit(1); } } -void print_decimal(decimal *d, char *orig, int actual, int want) +void print_decimal(decimal *d, const char *orig, int actual, int want) { char s[100]; int slen=sizeof(s); @@ -2218,38 +2234,41 @@ void test_d2s() dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); } -void test_s2d(char *s, char *orig, int ex) +void test_s2d(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; int res; sprintf(s1, "'%s'", s); + end= strend(s); printf("len=%2d %-30s => res=%d ", a.len, s1, - (res= string2decimal(s, &a, 0))); + (res= string2decimal(s, &a, &end))); print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2f(char *s, int ex) +void test_d2f(const char *s, int ex) { - char s1[100]; + char s1[100], *end; double x; int res; sprintf(s1, "'%s'", s); - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2double(&a, &x); if (full) dump_decimal(&a); printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x); check_result_code(res, ex); } -void test_d2b2d(char *str, int p, int s, char *orig, int ex) +void test_d2b2d(const char *str, int p, int s, const char *orig, int ex) { - char s1[100], buf[100]; + char s1[100], buf[100], *end; int res, i, size=decimal_bin_size(p, s); sprintf(s1, "'%s'", str); - string2decimal(str, &a, 0); + end= strend(str); + string2decimal(str, &a, &end); res=decimal2bin(&a, buf, p, s); printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size); if (full) @@ -2263,6 +2282,7 @@ void test_d2b2d(char *str, int p, int s, char *orig, int ex) print_decimal(&a, orig, res, ex); printf("\n"); } + void test_f2d(double from, int ex) { int res; @@ -2273,7 +2293,7 @@ void test_f2d(double from, int ex) printf("\n"); } -void test_ull2d(ulonglong from, char *orig, int ex) +void test_ull2d(ulonglong from, const char *orig, int ex) { char s[100]; int res; @@ -2285,7 +2305,7 @@ void test_ull2d(ulonglong from, char *orig, int ex) printf("\n"); } -void test_ll2d(longlong from, char *orig, int ex) +void test_ll2d(longlong from, const char *orig, int ex) { char s[100]; int res; @@ -2297,13 +2317,14 @@ void test_ll2d(longlong from, char *orig, int ex) printf("\n"); } -void test_d2ull(char *s, char *orig, int ex) +void test_d2ull(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; ulonglong x; int res; - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2ulonglong(&a, &x); if (full) dump_decimal(&a); longlong10_to_str(x,s1,10); @@ -2316,13 +2337,14 @@ void test_d2ull(char *s, char *orig, int ex) } } -void test_d2ll(char *s, char *orig, int ex) +void test_d2ll(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; longlong x; int res; - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2longlong(&a, &x); if (full) dump_decimal(&a); longlong10_to_str(x,s1,-10); @@ -2335,39 +2357,45 @@ void test_d2ll(char *s, char *orig, int ex) } } -void test_da(char *s1, char *s2, char *orig, int ex) +void test_da(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' + '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_add(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_ds(char *s1, char *s2, char *orig, int ex) +void test_ds(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' - '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_sub(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dc(char *s1, char *s2, int orig) +void test_dc(const char *s1, const char *s2, int orig) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' <=> '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_cmp(&a, &b); printf("%-40s => res=%d\n", s, res); if (orig != res) @@ -2377,26 +2405,30 @@ void test_dc(char *s1, char *s2, int orig) } } -void test_dm(char *s1, char *s2, char *orig, int ex) +void test_dm(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' * '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_mul(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dv(char *s1, char *s2, char *orig, int ex) +void test_dv(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' / '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_div(&a, &b, &c, 5); printf("%-40s => res=%d ", s, res); check_result_code(res, ex); @@ -2407,13 +2439,15 @@ void test_dv(char *s1, char *s2, char *orig, int ex) printf("\n"); } -void test_md(char *s1, char *s2, char *orig, int ex) +void test_md(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' %% '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_mod(&a, &b, &c); printf("%-40s => res=%d ", s, res); check_result_code(res, ex); @@ -2424,14 +2458,17 @@ void test_md(char *s1, char *s2, char *orig, int ex) printf("\n"); } -char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; +const char *round_mode[]= +{"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; -void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) +void test_ro(const char *s1, int n, decimal_round_mode mode, const char *orig, + int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res=decimal_round(&a, &b, n, mode); printf("%-40s => res=%d ", s, res); print_decimal(&b, orig, res, ex); @@ -2439,7 +2476,7 @@ void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) } -void test_mx(int precision, int frac, char *orig) +void test_mx(int precision, int frac, const char *orig) { char s[100]; sprintf(s, "%d, %d", precision, frac); @@ -2450,15 +2487,17 @@ void test_mx(int precision, int frac, char *orig) } -void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) +void test_pr(const char *s1, int prec, int dec, char filler, const char *orig, + int ex) { - char s[100]; + char s[100], *end; char s2[100]; int slen= sizeof(s2); int res; sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res= decimal2string(&a, s2, &slen, prec, dec, filler); printf("%-40s => res=%d '%s'", s, res, s2); check_result_code(res, ex); @@ -2471,12 +2510,13 @@ void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) } -void test_sh(char *s1, int shift, char *orig, int ex) +void test_sh(const char *s1, int shift, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res= decimal_shift(&a, shift); printf("%-40s => res=%d ", s, res); print_decimal(&a, orig, res, ex); @@ -2484,12 +2524,13 @@ void test_sh(char *s1, int shift, char *orig, int ex) } -void test_fr(char *s1, char *orig) +void test_fr(const char *s1, const char *orig) { - char s[100]; + char s[100], *end; sprintf(s, "'%s'", s1); printf("%-40s => ", s); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); decimal_optimize_fraction(&a); print_decimal(&a, orig, 0, 0); printf("\n"); From 3f0def331002aefd9415a6304fd310a6e0d2a6ed Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Feb 2005 18:23:25 +0100 Subject: [PATCH 05/12] ndb - fix to Time comparison ndb/src/common/util/NdbSqlUtil.cpp: remove stupid check --- ndb/src/common/util/NdbSqlUtil.cpp | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp index 7ecfb5194b8..4f1ee423c75 100644 --- a/ndb/src/common/util/NdbSqlUtil.cpp +++ b/ndb/src/common/util/NdbSqlUtil.cpp @@ -633,17 +633,8 @@ NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p return 0; } #else - char t1[4], t2[4]; - if (n1 == 3 && n2 == 3) - { - memcpy(t1, p1, 3); - memcpy(t2, p2, 3); - p1 = t1; - p2 = t2; - n1 = n2 = 4; - } #ifdef ndb_date_sol9x86_cc_xO3_madness - if (n2 >= 4) { // may access 4-th byte + if (n2 >= 3) { const uchar* v1 = (const uchar*)p1; const uchar* v2 = (const uchar*)p2; // from Field_newdate::val_int @@ -658,7 +649,7 @@ NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p return 0; } #else - if (n2 >= 4) { + if (n2 >= 3) { const uchar* v1 = (const uchar*)p1; const uchar* v2 = (const uchar*)p2; uint j1 = uint3korr(v1); @@ -712,7 +703,7 @@ NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p int NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) { - if (n2 >= 4) { // may access 4-th byte + if (n2 >= 3) { const uchar* v1 = (const uchar*)p1; const uchar* v2 = (const uchar*)p2; // from Field_time::val_int From 7b3df69baae0c4e161f06d368517e086db91257a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 19 Feb 2005 22:24:13 +0100 Subject: [PATCH 06/12] fix rpl_trunc_binlog to test the new behaviour --- mysql-test/r/rpl_trunc_binlog.result | 6 +++++- mysql-test/std_data/trunc_binlog.000001 | Bin 119 -> 174 bytes mysql-test/t/rpl_trunc_binlog.test | 20 +++++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index 5eb5f810a8f..2663fffe4d4 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -6,8 +6,12 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; stop slave; flush logs; +create table t1 (a int) engine=bdb; reset slave; start slave; show slave status; Slave_IO_State 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 Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 4 # # master-bin.000001 Yes No 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. A probable cause is that the master died while writing the transaction to its binary log. 0 79 # None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 4 # # master-bin.000002 Yes Yes 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. A probable cause is that the master died while writing the transaction to its binary log. 0 4 # None 0 No # +select * from t1; +a +drop table t1; diff --git a/mysql-test/std_data/trunc_binlog.000001 b/mysql-test/std_data/trunc_binlog.000001 index 2c2b4ec6ce4c40c23d347e46132170d2736db674..3da2490eab2aad9f8d493b7722e5c348b73c6b1c 100644 GIT binary patch literal 174 zcmeyDl$po0K-`Iuk%5818;Dten1O+r!9>qM&&XIeB{iuuT{kB`9W0EO02#vr#7rQg zG=SJ2tQ^Dx0ieMpsl_D>POk2re%vs1=0F+j>N4|+Q;SLzN(>ds5_3vZixo5sH34LX B7x4f9 literal 119 zcmeyDl$p1Ecdb1mBLf42HxRP`F#`iLgNdGjo}rm;N@`MRx^7N>I#?Jl0WxMk5Ho>{ Z(g0$AuySUoCZNG3sl_D>POk2regKU)5sm-= diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index b2e7e52f5e4..eec36532275 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -1,21 +1,28 @@ # We are testing if a binlog which contains BEGIN but not COMMIT (the -# master did while writing the transaction to the binlog) triggers an -# error on slave. So we use such a truncated binlog and simulate that +# master died while writing the transaction to the binlog) triggers a +# rollback on slave. So we use such a truncated binlog and simulate that # the master restarted after this. source include/master-slave.inc; connection slave; -# If we are not supporting transactions in the slave, the unfinished transaction -# won't cause any error, so we need to skip the test. In the 4.0 testsuite, the -# slave always runs without InnoDB, so we check for BDB. +# If we are not supporting transactions in the slave, the unfinished +# transaction won't cause any error, so we need to skip the test. In the 4.0 +# testsuite, the slave always runs without InnoDB, so we check for BDB. source include/have_bdb.inc; stop slave; + connection master; flush logs; system mv -f var/log/master-bin.000001 var/log/master-bin.000002; system cp std_data/trunc_binlog.000001 var/log/master-bin.000001; + connection slave; + +# truncated binlog contains: BEGIN; INSERT t1 VALUES (1); +# so let's create the table t1 on slave + +create table t1 (a int) engine=bdb; reset slave; start slave; # can't sync_with_master so we must sleep @@ -23,3 +30,6 @@ sleep 3; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 8 # 9 # 23 # 33 # show slave status; +select * from t1; +drop table t1; + From 3805001f7c1600b3c34a97478031e68b95cf9918 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 00:24:30 +0200 Subject: [PATCH 07/12] use dbug_print_decimal instead of DBUG_EXECUTE Portability fix Note: rpl_trunc_binlog fails, but Sergei has promised to fix it, so I will ignore it for now sql/field.cc: use dbug_print_decimal instead of DBUG_EXECUTE sql/item.h: Portability fix sql/my_decimal.cc: Fix error in last changeset (not pushed) --- sql/field.cc | 12 ++++++------ sql/item.h | 4 ---- sql/my_decimal.cc | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1da9bf6f7b0..a32b402cbdb 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1557,7 +1557,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) my_decimal *dec= (my_decimal*)decimal_value; int error= 0; DBUG_ENTER("Field_new_decimal::store_value"); - DBUG_EXECUTE("enter", print_decimal(dec);); + dbug_print_decimal("enter", "value: %s", dec); /* check that we do not try to write negative value in unsigned field */ if (unsigned_flag && decimal_value->sign()) @@ -1569,7 +1569,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) } DBUG_PRINT("info", ("saving with precision %d, scale: %d", (int)field_length, (int)decimals())); - DBUG_EXECUTE("info", print_decimal(dec);); + dbug_print_decimal("info", "value: %s", dec); if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, @@ -1581,8 +1581,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value) DBUG_PRINT("info", ("overflow")); set_value_on_overflow(&buff, dec->sign()); my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals()); - DBUG_EXECUTE("info", print_decimal_buff(&buff, (byte *) ptr, bin_size);); - DBUG_RETURN(1); + error= 1; } DBUG_EXECUTE("info", print_decimal_buff(dec, (byte *) ptr, bin_size);); DBUG_RETURN(error); @@ -1616,7 +1615,7 @@ int Field_new_decimal::store(const char *from, uint length, break; } - DBUG_EXECUTE("info", print_decimal(&decimal_value);); + dbug_print_decimal("enter", "value: %s", &decimal_value); store_value(&decimal_value); DBUG_RETURN(err); } @@ -1708,7 +1707,8 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value, field_length, decimals()); - DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, bin_size);); + DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, + bin_size);); DBUG_RETURN(decimal_value); } diff --git a/sql/item.h b/sql/item.h index 6ca61d21467..2b719840357 100644 --- a/sql/item.h +++ b/sql/item.h @@ -463,11 +463,7 @@ public: longlong val_int(); String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); -#ifdef __WIN__ bool is_null(); -#else - inline bool is_null(); -#endif void print(String *str); inline void make_field(Send_field *field) diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 3e3538a1da9..334c40c0f70 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -228,7 +228,7 @@ void dbug_print_decimal(const char *tag, const char *format, my_decimal *val) str.set("NULL", 4, &my_charset_bin); else my_decimal2string(0, val, 0, 0, 0, &str); - DBUG_PRINT(tag, (format, val)); + DBUG_PRINT(tag, (format, (char*) str.ptr())); } #endif From da4604f9e8fa42c8e7c5627b692e0ac6d5409802 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 04:36:22 +0300 Subject: [PATCH 08/12] CPPFLAGS is substituted with CXXFLAGS to work with older automake. Serg, now you can enable server-tools/instance-manager. server-tools/instance-manager/Makefile.am: The famous CPPFLAGS (aka "upgrade automake") thing was removed. Upon Brian's request. --- server-tools/instance-manager/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am index c9c9009a8ec..ebaccd194dd 100644 --- a/server-tools/instance-manager/Makefile.am +++ b/server-tools/instance-manager/Makefile.am @@ -25,7 +25,7 @@ DEFS= -DMYSQL_INSTANCE_MANAGER -DMYSQL_SERVER noinst_LIBRARIES= liboptions.a libnet.a -liboptions_a_CPPFLAGS= $(CPPFLAGS) \ +liboptions_a_CXXFLAGS= $(CXXFLAGS) \ -DDEFAULT_PID_FILE_NAME="$(localstatedir)/mysqlmanager.pid" \ -DDEFAULT_LOG_FILE_NAME="$(localstatedir)/mysqlmanager.log" \ -DDEFAULT_SOCKET_FILE_NAME="$(localstatedir)/mysqlmanager.sock" \ From 1683fc96734d449980b7489bbf2afad63c4ae853 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 16:55:11 +0100 Subject: [PATCH 09/12] underflow in decimal_round fixed --- strings/decimal.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/strings/decimal.c b/strings/decimal.c index 212bd7204f6..28c6ace658f 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#line __LINE__ "decimal.c" +#line 18 "decimal.c" /* ======================================================================= @@ -113,8 +113,8 @@ typedef longlong dec2; #define DIG_PER_DEC1 9 #define DIG_MASK 100000000 #define DIG_BASE 1000000000 -#define DIG_MAX 999999999 -#define DIG_BASE2 LL(1000000000000000000) +#define DIG_MAX (DIG_BASE-1) +#define DIG_BASE2 ((dec2)DIG_BASE * (dec2)DIG_BASE) #define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1) static const dec1 powers10[DIG_PER_DEC1+1]={ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; @@ -1415,6 +1415,11 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode else *(++buf1)=DIG_BASE; } + else if (frac0+intg0==0) + { + decimal_make_zero(to); + return E_DEC_OK; + } } else { @@ -2666,11 +2671,12 @@ int main() test_md("234.567","10.555","2.357", 0); test_md("-234.567","10.555","-2.357", 0); test_md("234.567","-10.555","2.357", 0); - if (full) + c.buf[1]=0x3ABECA; + test_md("99999999999999999999999999999999999999","3","0", 0); + if (c.buf[1] != 0x3ABECA) { - c.buf[1]=0x3ABECA; - test_md("99999999999999999999999999999999999999","3","0", 0); - printf("%X\n", c.buf[1]); + printf("%X - overflow\n", c.buf[1]); + exit(1); } printf("==== decimal2bin/bin2decimal ====\n"); @@ -2741,6 +2747,16 @@ int main() test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000", 0); test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000", 0); + b.buf[0]=DIG_BASE+1; + b.buf++; + test_ro(".3", 0, HALF_UP, "0", 0); + b.buf--; + if (b.buf[0] != DIG_BASE+1) + { + printf("%d - underflow\n", b.buf[0]); + exit(1); + } + printf("==== max_decimal ====\n"); test_mx(1,1,"0.9"); test_mx(1,0,"9"); From 10db96fe432886f15bc489b6f27540b6fa3463a7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 17:25:22 +0100 Subject: [PATCH 10/12] decimal format documented --- strings/decimal.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/strings/decimal.c b/strings/decimal.c index 28c6ace658f..e6d2d9b14dd 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -107,6 +107,21 @@ #include #include +/* + Internally decimal numbers are stored base 10^9 (see DIG_BASE below) + So one "decimal_digit" is + + 0 < decimal_digit <= DIG_MAX < DIG_BASE + + in the struct st_decimal: + + intg is the number of *decimal* digits (NOT number of decimal_digit's !) + before the point + frac - number of decimal digits after the point + buf is an array of decimal_digit's + len is the length of buf (length of allocated space) in decimal_digit's, + not in bytes +*/ typedef decimal_digit dec1; typedef longlong dec2; @@ -1073,6 +1088,68 @@ int decimal2longlong(decimal *from, longlong *to) RETURN VALUE E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW + + DESCRIPTION + for storage decimal numbers are converted to the "binary" format. + + This format has the following properties: + 1. length of the binary representation depends on the {precision, scale} + as provided by the caller and NOT on the intg/frac of the decimal to + convert. + 2. binary representations of the same {precision, scale} can be compared + with memcmp - with the same result as decimal_cmp() of the original + decimals (not taking into account possible precision loss during + conversion). + + This binary format is as follows: + 1. First the number is converted to have a requested precision and scale. + 2. Every full DIG_PER_DEC1 digits of intg part are stored in 4 bytes + as is + 3. The first intg % DIG_PER_DEC1 digits are stored in the reduced + number of bytes (enough bytes to store this number of digits - + see dig2bytes) + 4. same for frac - full decimal_digit's are stored as is, + the last frac % DIG_PER_DEC1 digits - in the reduced number of bytes. + 5. If the number is negative - every byte is inversed. + 5. The very first bit of the resulting byte array is inverted (because + memcmp compares unsigned bytes, see property 2 above) + + Example: + + 1234567890.1234 + + internally is represented as 3 decimal_digit's + + 1 234567890 123400000 + + (assuming we want a binary representation with precision=14, scale=4) + in hex it's + + 00-00-00-01 0D-FB-38-D2 07-5A-EF-40 + + now, middle decimal_digit is full - it stores 9 decimal digits. It goes + into binary representation as is: + + + ........... 0D-FB-38-D2 ............ + + First decimal_digit has only one decimal digit. We can store one digit in + one byte, no need to waste four: + + 01 0D-FB-38-D2 ............ + + now, last digit. It's 123400000. We can store 1234 in two bytes: + + 01 0D-FB-38-D2 04-D2 + + So, we've packed 12 bytes number in 7 bytes. + And now we invert the highest bit to get the final result: + + 81 0D FB 38 D2 04 D2 + + And for -1234567890.1234 it would be + + 7E F2 04 37 2D FB 2D */ int decimal2bin(decimal *from, char *to, int precision, int frac) { From a0a20345b9869731cac43438ed5c23709aa6fc14 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 20:08:33 +0100 Subject: [PATCH 11/12] portability fixes mysql-test/r/mysqlbinlog.result: result fixed --- include/config-win.h | 3 --- include/my_sys.h | 3 ++- mysql-test/r/mysqlbinlog.result | 8 ++++++-- mysys/my_mmap.c | 4 ++-- sql/log.cc | 14 ++++++-------- sql/sql_class.h | 7 ++++++- 6 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 475141a1989..ba1a987f14c 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -310,9 +310,6 @@ inline double ulonglong2double(ulonglong value) #define HAVE_SETFILEPOINTER #define HAVE_VIO -#define HAME_MMAP /* in mysys/my_mmap.c */ -#define HAVE_GETPAGESIZE /* in mysys/my_mmap.c */ - #ifdef NOT_USED #define HAVE_SNPRINTF /* Gave link error */ #define _snprintf snprintf diff --git a/include/my_sys.h b/include/my_sys.h index 9cce13e53dd..498a1bd30fe 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -796,7 +796,7 @@ void my_free_open_file_info(void); ulonglong my_getsystime(void); my_bool my_gethwaddr(uchar *to); -#ifdef HAVE_MMAP +#ifdef HAVE_SYS_MMAN_H #include #ifndef MAP_NOSYNC @@ -815,6 +815,7 @@ my_bool my_gethwaddr(uchar *to); #define MAP_NOSYNC 0x0800 #define MAP_FAILED ((void *)-1) #define MS_SYNC 0x0000 +#define HAVE_MMAP int my_getpagesize(void); void *my_mmap(void *, size_t, int, int, int, my_off_t); diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index ee0047934ab..df117479814 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -111,10 +111,14 @@ insert into t1 values ("Alas"); /*!40019 SET @@session.max_insert_delayed_threads=0*/; ROLLBACK; use test; -SET TIMESTAMP=1065204671; +SET TIMESTAMP=1108844556; BEGIN; +SET TIMESTAMP=1108844555; +insert t1 values (1); /*!40019 SET @@session.max_insert_delayed_threads=0*/; use test; -SET TIMESTAMP=1065204671; +SET TIMESTAMP=1108844556; BEGIN; +SET TIMESTAMP=1108844555; +insert t1 values (1); drop table t1, t2; diff --git a/mysys/my_mmap.c b/mysys/my_mmap.c index 883181edd6c..0225e7fac24 100644 --- a/mysys/my_mmap.c +++ b/mysys/my_mmap.c @@ -16,7 +16,7 @@ #include "mysys_priv.h" -#ifdef HAVE_MMAP +#ifdef HAVE_SYS_MMAN_H /* system msync() only syncs mmap'ed area to fs cache. @@ -84,6 +84,6 @@ int my_msync(int fd, void *addr, size_t len, int flags) } #endif -#error "no mmap!" +#warning "no mmap!" #endif diff --git a/sql/log.cc b/sql/log.cc index cb776cff0e9..b048323aa76 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2415,6 +2415,7 @@ void sql_print_information(const char *format, ...) DBUG_VOID_RETURN; } +#ifdef HAVE_MMAP /********* transaction coordinator log for 2pc - mmap() based solution *******/ /* @@ -2460,10 +2461,6 @@ uint opt_tc_log_size=TC_LOG_MIN_SIZE; uint tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_page_waits=0, tc_log_cur_pages_used=0; -TC_LOG *tc_log; -TC_LOG_MMAP tc_log_mmap; -TC_LOG_DUMMY tc_log_dummy; - int TC_LOG_MMAP::open(const char *opt_name) { uint i; @@ -2473,12 +2470,8 @@ int TC_LOG_MMAP::open(const char *opt_name) DBUG_ASSERT(total_ha_2pc > 1); DBUG_ASSERT(opt_name && opt_name[0]); -#ifdef HAVE_GETPAGESIZE tc_log_page_size= my_getpagesize(); DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0); -#else - tc_log_page_size= TC_LOG_PAGE_SIZE; -#endif fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME); fd= my_open(logname, O_RDWR, MYF(0)); @@ -2861,6 +2854,11 @@ err1: "--tc-heuristic-recover={commit|rollback}"); return 1; } +#endif + +TC_LOG *tc_log; +TC_LOG_DUMMY tc_log_dummy; +TC_LOG_MMAP tc_log_mmap; /* Perform heuristic recovery, if --tc-heuristic-recover was used diff --git a/sql/sql_class.h b/sql/sql_class.h index 05fd1fdea58..34019e73f96 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -80,6 +80,7 @@ class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging void unlog(ulong cookie, my_xid xid) { } }; +#ifdef HAVE_MMAP class TC_LOG_MMAP: public TC_LOG { private: @@ -103,7 +104,8 @@ class TC_LOG_MMAP: public TC_LOG char logname[FN_REFLEN]; File fd; - uint file_length, npages, inited; + my_off_t file_length; + uint npages, inited; uchar *data; struct st_page *pages, *syncing, *active, *pool, *pool_last; /* @@ -128,6 +130,9 @@ class TC_LOG_MMAP: public TC_LOG int sync(); int overflow(); }; +#else +#define TC_LOG_MMAP TC_LOG_DUMMY +#endif extern TC_LOG *tc_log; extern TC_LOG_MMAP tc_log_mmap; From b3b5f8fb651e40506ab51acb12796b0f7d8d98ef Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Feb 2005 22:52:28 +0300 Subject: [PATCH 12/12] Fix confusing comments. sql/examples/ha_example.cc: fix comments, referring to renamed function sql/ha_federated.cc: fix comments, referring to renamed function --- sql/examples/ha_example.cc | 2 +- sql/ha_federated.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index cb0780ea74d..d043a66e71a 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -414,7 +414,7 @@ int ha_example::rnd_next(byte *buf) position() is called after each call to rnd_next() if the data needs to be ordered. You can do something like the following to store the position: - ha_store_ptr(ref, ref_length, current_position); + my_store_ptr(ref, ref_length, current_position); The server uses ref to store data. ref_length in the above case is the size needed to store current_position. ref is just a byte array diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 695c71677c0..518f59eb853 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1503,7 +1503,7 @@ int ha_federated::rnd_next(byte *buf) /* 'position()' is called after each call to rnd_next() if the data needs to be ordered. You can do something like the following to store the position: - ha_store_ptr(ref, ref_length, current_position); + my_store_ptr(ref, ref_length, current_position); The server uses ref to store data. ref_length in the above case is the size needed to store current_position. ref is just a byte array that the server @@ -1516,7 +1516,7 @@ int ha_federated::rnd_next(byte *buf) void ha_federated::position(const byte *record) { DBUG_ENTER("ha_federated::position"); - //ha_store_ptr Add seek storage + //my_store_ptr Add seek storage *(MYSQL_ROW_OFFSET *)ref=current_position; // ref is always aligned DBUG_VOID_RETURN; }