diff options
author | unknown <bell@sanja.is.com.ua> | 2004-02-14 13:31:39 +0200 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-02-14 13:31:39 +0200 |
commit | 6826a55b1da73770ce067972efafc00f9d2f6670 (patch) | |
tree | 5a43e43d6a139a343cb71c89c1209240d9287db0 | |
parent | fab7113f8398ba41d5e54e32dc0b3259a6297dfc (diff) | |
parent | 4ec12a5e55d5f2db27a5c0ce93c7e74254d652a4 (diff) | |
download | mariadb-git-6826a55b1da73770ce067972efafc00f9d2f6670.tar.gz |
merge
sql/item.h:
Auto merged
sql/item_sum.h:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_prepare.cc:
Auto merged
38 files changed, 501 insertions, 488 deletions
diff --git a/configure.in b/configure.in index 9cdb9d209c2..67a751f7e17 100644 --- a/configure.in +++ b/configure.in @@ -1828,7 +1828,7 @@ AC_CHECK_FUNCS(alarm bmove \ strtol strtoul strtoll strtoull snprintf tempnam thr_setconcurrency \ gethostbyaddr_r gethostbyname_r getpwnam \ bfill bzero bcmp strstr strpbrk strerror \ - tell atod memcpy memmove \ + tell isinf memcpy memmove \ setupterm strcasecmp sighold vidattr lrand48 localtime_r gmtime_r \ sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \ pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \ diff --git a/include/m_ctype.h b/include/m_ctype.h index 88c3418fc0d..9c843382fc7 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -391,7 +391,11 @@ extern my_bool my_parse_charset_xml(const char *bug, uint len, #define use_mb(s) ((s)->cset->ismbchar != NULL) #define my_ismbchar(s, a, b) ((s)->cset->ismbchar((s), (a), (b))) +#ifdef USE_MB #define my_mbcharlen(s, a) ((s)->cset->mbcharlen((s),(a))) +#else +#define my_mbcharlen(s, a) 1 +#endif #define my_caseup(s, a, l) ((s)->cset->caseup((s), (a), (l))) #define my_casedn(s, a, l) ((s)->cset->casedn((s), (a), (l))) diff --git a/include/m_string.h b/include/m_string.h index d72342fb3c1..ac2aae37704 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -201,7 +201,7 @@ extern int strcmp(const char *, const char *); extern size_t strlen(const char *); #endif #endif -#ifndef HAVE_STRNLEN +#ifndef HAVE_STRNLEN extern uint strnlen(const char *s, uint n); #endif @@ -215,7 +215,9 @@ extern char *strstr(const char *, const char *); #endif extern int is_prefix(const char *, const char *); -/* Conversion rutins */ +/* Conversion routines */ +double my_strtod(const char *str, char **end); +double my_atof(const char *nptr); #ifdef USE_MY_ITOA extern char *my_itoa(int val,char *dst,int radix); diff --git a/include/my_global.h b/include/my_global.h index c9660d4d649..41e3636116a 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -522,7 +522,7 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_EXTCHAR '.' #define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ #define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ -#define FN_PARENTDIR ".." /* Parentdirectory; Must be a string */ +#define FN_PARENTDIR ".." /* Parent directory; Must be a string */ #define FN_DEVCHAR ':' #ifndef FN_LIBCHAR @@ -581,14 +581,6 @@ typedef SOCKET_SIZE_TYPE size_socket; /* Some defines of functions for portability */ -#ifndef HAVE_ATOD -#define atod atof -#endif -#ifdef USE_MY_ATOF -#define atof my_atof -extern void init_my_atof(void); -extern double my_atof(const char*); -#endif #undef remove /* Crashes MySQL on SCO 5.0.0 */ #ifndef __WIN__ #ifdef OS2 @@ -677,6 +669,10 @@ extern double my_atof(const char*); #define FLT_MAX ((float)3.40282346638528860e+38) #endif +#ifndef HAVE_ISINF +#define isinf(X) 0 +#endif + /* Max size that must be added to a so that we know Size to make adressable obj. diff --git a/include/mysql.h b/include/mysql.h index 0bb42c7f5eb..cd5d01d6f44 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -534,6 +534,8 @@ typedef struct st_mysql_stmt char *query; /* query buffer */ MEM_ROOT mem_root; /* root allocations */ my_ulonglong last_fetched_column; /* last fetched column */ + my_ulonglong affected_rows; /* copy of mysql->affected_rows + after statement execution */ unsigned long stmt_id; /* Id for prepared statement */ unsigned int last_errno; /* error code */ unsigned int param_count; /* parameters count */ diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 1cffae4dc56..678abc91859 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -32,7 +32,7 @@ target_sources = libmysql.c password.c manager.c \ get_password.c errmsg.c mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \ - strmake.lo strend.lo \ + strmake.lo strend.lo strtod.lo \ strnlen.lo strfill.lo is_prefix.lo \ int2str.lo str2int.lo strinstr.lo strcont.lo \ strcend.lo bcmp.lo ctype-latin1.lo \ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 5c5898dfd7d..859ec92f793 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2010,6 +2010,7 @@ static my_bool execute(MYSQL_STMT * stmt, char *packet, ulong length) set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); DBUG_RETURN(1); } + stmt->affected_rows= mysql->affected_rows; DBUG_RETURN(0); } @@ -2106,7 +2107,7 @@ ulong STDCALL mysql_param_count(MYSQL_STMT * stmt) my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt) { - return stmt->mysql->last_used_con->affected_rows; + return stmt->affected_rows; } @@ -3173,6 +3174,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) DBUG_RETURN(0); } mysql->affected_rows= result->row_count= result->data->rows; + stmt->affected_rows= result->row_count; result->data_cursor= result->data->data; result->fields= stmt->fields; result->field_count= stmt->field_count; diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 81235ce0c22..188227c21f9 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -251,7 +251,7 @@ int emb_next_result(MYSQL *mysql) DBUG_ENTER("emb_next_result"); if (emb_advanced_command(mysql, COM_QUERY,0,0, - thd->query_rest,thd->query_rest_length,1) + thd->query_rest.ptr(),thd->query_rest.length(),1) || emb_mysql_read_query_result(mysql)) DBUG_RETURN(1); @@ -689,7 +689,10 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) mysql->affected_rows= affected_rows; mysql->insert_id= id; if (message) + { strmake(thd->net.last_error, message, sizeof(thd->net.last_error)-1); + mysql->info= thd->net.last_error; + } DBUG_VOID_RETURN; } @@ -762,11 +765,6 @@ bool Protocol::net_store_data(const char *from, uint length) return false; } -char *memdup_mysql(struct st_mysql *mysql, const char*data, int length) -{ - return memdup_root(&mysql->field_alloc, data, length); -} - #if 0 /* The same as Protocol::net_store_data but does the converstion */ diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 658a7b8f5f6..8b7178993a7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -167,3 +167,5 @@ select hex(s1) from t1; hex(s1) 41 drop table t1; +create table t1 (a char(160) character set utf8, primary key(a)); +ERROR HY000: Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the storage engine doesn't support unique sub keys diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index fd9e2a1f42b..0e642f48f3c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -186,7 +186,7 @@ create table ```a` (i int); /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=NO_AUTO_VALUE_ON_ZERO */; DROP TABLE IF EXISTS ```a`; -CREATE TABLE ``a` ( +CREATE TABLE ```a` ( `i` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 290f916ae72..235c6cd0ecf 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -265,3 +265,51 @@ c decimal(4,3) YES NULL d double(4,3) YES NULL f float(4,3) YES NULL drop table t1; +SET sql_mode=''; +SET sql_quote_show_create=OFF; +CREATE TABLE ```ab``cd``` (i INT); +SHOW CREATE TABLE ```ab``cd```; +Table Create Table +`ab`cd` CREATE TABLE ```ab``cd``` ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE ```ab``cd```; +CREATE TABLE ```ab````cd``` (i INT); +SHOW CREATE TABLE ```ab````cd```; +Table Create Table +`ab``cd` CREATE TABLE ```ab````cd``` ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE ```ab````cd```; +CREATE TABLE ```a` (i INT); +SHOW CREATE TABLE ```a`; +Table Create Table +`a CREATE TABLE ```a` ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE ```a`; +SET sql_mode='ANSI_QUOTES'; +CREATE TABLE """a" (i INT); +SHOW CREATE TABLE """a"; +Table Create Table +"a CREATE TABLE """a" ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE """a"; +SET sql_mode=''; +SET sql_quote_show_create=OFF; +CREATE TABLE t1 (i INT); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE t1 ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE `table` (i INT); +SHOW CREATE TABLE `table`; +Table Create Table +table CREATE TABLE `table` ( + i int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `table`; +SET sql_quote_show_create=ON; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 0615de99b7a..49b1ed94757 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -98,3 +98,10 @@ create table t1 (s1 text character set utf8); insert into t1 values (0x41FF); select hex(s1) from t1; drop table t1; + +# +# Bug 2699 +# UTF8 breaks primary keys for cols > 85 characters +# +--error 1089 +create table t1 (a char(160) character set utf8, primary key(a)); diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index d262f02c978..1d64cfd2105 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -142,3 +142,43 @@ drop table t1; create table t1 (c decimal(3,3), d double(3,3), f float(3,3)); show columns from t1; drop table t1; + +# +# Test for Bug #2593 "SHOW CREATE TABLE doesn't properly double quotes" +# + +SET sql_mode=''; +SET sql_quote_show_create=OFF; + +CREATE TABLE ```ab``cd``` (i INT); +SHOW CREATE TABLE ```ab``cd```; +DROP TABLE ```ab``cd```; + +CREATE TABLE ```ab````cd``` (i INT); +SHOW CREATE TABLE ```ab````cd```; +DROP TABLE ```ab````cd```; + +CREATE TABLE ```a` (i INT); +SHOW CREATE TABLE ```a`; +DROP TABLE ```a`; + +SET sql_mode='ANSI_QUOTES'; + +CREATE TABLE """a" (i INT); +SHOW CREATE TABLE """a"; +DROP TABLE """a"; + +# to test quotes around keywords.. : + +SET sql_mode=''; +SET sql_quote_show_create=OFF; + +CREATE TABLE t1 (i INT); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE `table` (i INT); +SHOW CREATE TABLE `table`; +DROP TABLE `table`; + +SET sql_quote_show_create=ON; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 08737221fb2..52b7f153e0d 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -627,7 +627,7 @@ writes: %ld r_requests: %ld reads: %ld", a pointer to the last element. */ -static inline void link_into_queue(KEYCACHE_WQUEUE *wqueue, +static void link_into_queue(KEYCACHE_WQUEUE *wqueue, struct st_my_thread_var *thread) { struct st_my_thread_var *last; @@ -662,7 +662,7 @@ static inline void link_into_queue(KEYCACHE_WQUEUE *wqueue, See NOTES for link_into_queue */ -static inline void unlink_from_queue(KEYCACHE_WQUEUE *wqueue, +static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue, struct st_my_thread_var *thread) { KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id)); diff --git a/mysys/my_new.cc b/mysys/my_new.cc index ec27502d8aa..14423c3afd5 100644 --- a/mysys/my_new.cc +++ b/mysys/my_new.cc @@ -19,10 +19,10 @@ with gcc 3.0.x to avoid including libstdc++ */ -#ifdef USE_MYSYS_NEW - #include "mysys_priv.h" +#ifdef USE_MYSYS_NEW + void *operator new (size_t sz) { return (void *) malloc (sz ? sz : 1); diff --git a/mytest-old.c b/mytest-old.c deleted file mode 100644 index 8b4029f5e1e..00000000000 --- a/mytest-old.c +++ /dev/null @@ -1,169 +0,0 @@ -/*C4*/ -/****************************************************************/ -/* Author: Jethro Wright, III TS : 3/ 4/1998 9:15 */ -/* Date: 02/18/1998 */ -/* mytest.c : do some testing of the libmySQL.DLL.... */ -/* */ -/* History: */ -/* 02/18/1998 jw3 also sprach zarathustra.... */ -/****************************************************************/ - - -#include <windows.h> -#include <stdio.h> -#include <string.h> - -#include <mysql.h> - -#define DEFALT_SQL_STMT "SELECT * FROM db" -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - - -/******************************************************** -** -** main :- -** -********************************************************/ - -int -main( int argc, char * argv[] ) -{ - - char szSQL[ 200 ], aszFlds[ 25 ][ 25 ], * pszT, szDB[ 50 ] ; - int i, j, k, l, x ; - MYSQL * myData ; - MYSQL_RES * res ; - MYSQL_FIELD * fd ; - MYSQL_ROW row ; - - //....just curious.... - printf( "sizeof( MYSQL ) == %d\n", sizeof( MYSQL ) ) ; - if ( argc == 2 ) - { - strcpy( szDB, argv[ 1 ] ) ; - strcpy( szSQL, DEFALT_SQL_STMT ) ; - if (!strcmp(szDB,"--debug")) - { - strcpy( szDB, "mysql" ) ; - printf("Some mysql struct information (size and offset):\n"); - printf("net:\t%3d %3d\n",sizeof(myData->net),offsetof(MYSQL,net)); - printf("host:\t%3d %3d\n",sizeof(myData->host),offsetof(MYSQL,host)); - printf("port:\t%3d %3d\n",sizeof(myData->port),offsetof(MYSQL,port)); - printf("protocol_version:\t%3d %3d\n",sizeof(myData->protocol_version), - offsetof(MYSQL,protocol_version)); - printf("thread_id:\t%3d %3d\n",sizeof(myData->thread_id), - offsetof(MYSQL,thread_id)); - printf("affected_rows:\t%3d %3d\n",sizeof(myData->affected_rows), - offsetof(MYSQL,affected_rows)); - printf("packet_length:\t%3d %3d\n",sizeof(myData->packet_length), - offsetof(MYSQL,packet_length)); - printf("status:\t%3d %3d\n",sizeof(myData->status), - offsetof(MYSQL,status)); - printf("fields:\t%3d %3d\n",sizeof(myData->fields), - offsetof(MYSQL,fields)); - printf("field_alloc:\t%3d %3d\n",sizeof(myData->field_alloc), - offsetof(MYSQL,field_alloc)); - printf("free_me:\t%3d %3d\n",sizeof(myData->free_me), - offsetof(MYSQL,free_me)); - printf("options:\t%3d %3d\n",sizeof(myData->options), - offsetof(MYSQL,options)); - puts(""); - } - } - else if ( argc > 2 ) { - strcpy( szDB, argv[ 1 ] ) ; - strcpy( szSQL, argv[ 2 ] ) ; - } - else { - strcpy( szDB, "mysql" ) ; - strcpy( szSQL, DEFALT_SQL_STMT ) ; - } - //.... - - if ( (myData = mysql_init((MYSQL*) 0)) && - mysql_real_connect( myData, NULL, NULL, NULL, NULL, MYSQL_PORT, - NULL, 0 ) ) - { - if ( mysql_select_db( myData, szDB ) < 0 ) { - printf( "Can't select the %s database !\n", szDB ) ; - mysql_close( myData ) ; - return 2 ; - } - } - else { - printf( "Can't connect to the mysql server on port %d !\n", - MYSQL_PORT ) ; - mysql_close( myData ) ; - return 1 ; - } - //.... - if ( ! mysql_query( myData, szSQL ) ) { - res = mysql_store_result( myData ) ; - i = (int) mysql_num_rows( res ) ; l = 1 ; - printf( "Query: %s\nNumber of records found: %ld\n", szSQL, i ) ; - //....we can get the field-specific characteristics here.... - for ( x = 0 ; fd = mysql_fetch_field( res ) ; x++ ) - strcpy( aszFlds[ x ], fd->name ) ; - //.... - while ( row = mysql_fetch_row( res ) ) { - j = mysql_num_fields( res ) ; - printf( "Record #%ld:-\n", l++ ) ; - for ( k = 0 ; k < j ; k++ ) - printf( " Fld #%d (%s): %s\n", k + 1, aszFlds[ k ], - (((row[k]==NULL)||(!strlen(row[k])))?"NULL":row[k])) ; - puts( "==============================\n" ) ; - } - mysql_free_result( res ) ; - } - else printf( "Couldn't execute %s on the server !\n", szSQL ) ; - //.... - puts( "==== Diagnostic info ====" ) ; - pszT = mysql_get_client_info() ; - printf( "Client info: %s\n", pszT ) ; - //.... - pszT = mysql_get_host_info( myData ) ; - printf( "Host info: %s\n", pszT ) ; - //.... - pszT = mysql_get_server_info( myData ) ; - printf( "Server info: %s\n", pszT ) ; - //.... - res = mysql_list_processes( myData ) ; l = 1 ; - if (res) - { - for ( x = 0 ; fd = mysql_fetch_field( res ) ; x++ ) - strcpy( aszFlds[ x ], fd->name ) ; - while ( row = mysql_fetch_row( res ) ) { - j = mysql_num_fields( res ) ; - printf( "Process #%ld:-\n", l++ ) ; - for ( k = 0 ; k < j ; k++ ) - printf( " Fld #%d (%s): %s\n", k + 1, aszFlds[ k ], - (((row[k]==NULL)||(!strlen(row[k])))?"NULL":row[k])) ; - puts( "==============================\n" ) ; - } - } - else - { - printf("Got error %s when retreiving processlist\n",mysql_error(myData)); - } - //.... - res = mysql_list_tables( myData, "%" ) ; l = 1 ; - for ( x = 0 ; fd = mysql_fetch_field( res ) ; x++ ) - strcpy( aszFlds[ x ], fd->name ) ; - while ( row = mysql_fetch_row( res ) ) { - j = mysql_num_fields( res ) ; - printf( "Table #%ld:-\n", l++ ) ; - for ( k = 0 ; k < j ; k++ ) - printf( " Fld #%d (%s): %s\n", k + 1, aszFlds[ k ], - (((row[k]==NULL)||(!strlen(row[k])))?"NULL":row[k])) ; - puts( "==============================\n" ) ; - } - //.... - pszT = mysql_stat( myData ) ; - puts( pszT ) ; - //.... - mysql_close( myData ) ; - return 0 ; - -} diff --git a/sql-common/client.c b/sql-common/client.c index 1c58bd04d0e..10df4653601 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1420,7 +1420,8 @@ static MYSQL_METHODS client_methods= cli_read_binary_rows, cli_unbuffered_fetch, NULL, - cli_read_statistic + cli_read_statistic, + cli_read_query_result #endif }; diff --git a/sql/gstream.cc b/sql/gstream.cc index a97ed9cae03..17b85af22bd 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -101,7 +101,7 @@ int GTextReadStream::get_next_number(double *d) char *endptr; - *d = strtod(cur, &endptr); + *d = my_strtod(cur, &endptr); if (endptr) { diff --git a/sql/init.cc b/sql/init.cc index 033dfd72843..084db57f8aa 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -34,9 +34,6 @@ void unireg_init(ulong options) current_pid=(ulong) getpid(); /* Save for later ref */ init_time(); /* Init time-functions (read zone) */ -#ifdef USE_MY_ATOF - init_my_atof(); /* use our atof */ -#endif #ifndef EMBEDDED_LIBRARY my_abort_hook=unireg_abort; /* Abort with close of databases */ #endif diff --git a/sql/item.h b/sql/item.h index 2ad85832747..9bdde1c9847 100644 --- a/sql/item.h +++ b/sql/item.h @@ -449,7 +449,7 @@ class Item_real :public Item public: const double value; // Item_real() :value(0) {} - Item_real(const char *str_arg,uint length) :value(atof(str_arg)) + Item_real(const char *str_arg,uint length) :value(my_atof(str_arg)) { name=(char*) str_arg; decimals=(uint8) nr_of_decimals(str_arg); diff --git a/sql/item_func.cc b/sql/item_func.cc index 34a61ba0353..82ff9de4a56 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2254,7 +2254,7 @@ double user_var_entry::val(my_bool *null_value) case INT_RESULT: return (double) *(longlong*) value; case STRING_RESULT: - return atof(value); // This is null terminated + return my_atof(value); // This is null terminated case ROW_RESULT: DBUG_ASSERT(1); // Impossible break; diff --git a/sql/item_sum.h b/sql/item_sum.h index 06989f30ae5..840ed1d1f7d 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -738,7 +738,7 @@ class Item_func_group_concat : public Item_sum enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} const char *func_name() const { return "group_concat"; } - enum Type type() const { return SUM_FUNC_ITEM; } + enum Type type() const { return SUM_FUNC_ITEM; } virtual Item_result result_type () const { return STRING_RESULT; } void clear(); bool add(); @@ -750,7 +750,7 @@ class Item_func_group_concat : public Item_sum double val() { String *res; res=val_str(&str_value); - return res ? atof(res->c_ptr()) : 0.0; + return res ? my_atof(res->c_ptr()) : 0.0; } longlong val_int() { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 73cc8b9ce03..ed56924775e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -764,6 +764,8 @@ uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match); uint check_word(TYPELIB *lib, const char *val, const char *end, const char **end_of_word); +bool is_keyword(const char *name, uint len); + #define MY_DB_OPT_FILE "db.opt" bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 9e73e06d9c6..3c9563165fe 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -225,7 +225,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) info->decimals++; if (str == end) { - info->dval = atod(begin); + info->dval = my_atof(begin); return 1; } } diff --git a/sql/sql_class.h b/sql/sql_class.h index 93703acc97b..a3f3737e46f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -591,8 +591,7 @@ public: struct st_mysql_bind *client_params; char *extra_data; ulong extra_length; - char *query_rest; - uint32 query_rest_length; + String query_rest; #endif NET net; // client connection descriptor MEM_ROOT warn_root; // For warnings and errors diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f145a232809..7679bccebfd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -181,6 +181,23 @@ static int find_keyword(LEX *lex, uint len, bool function) return 0; } +/* + Check if name is a keyword + + SYNOPSIS + is_keyword() + name checked name + len length of checked name + + RETURN VALUES + 0 name is a keyword + 1 name isn't a keyword +*/ + +bool is_keyword(const char *name, uint len) +{ + return get_hash_symbol(name,len,0)!=0; +} /* make a copy of token before ptr and set yytoklen */ @@ -427,7 +444,6 @@ inline static uint int_token(const char *str,uint length) return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger; } - /* yylex remember the following states from the following yylex() @@ -678,10 +694,9 @@ int yylex(void *arg, void *yythd) char quote_char= c; // Used char lex->tok_start=lex->ptr; // Skip first ` while ((c=yyGet())) - { -#ifdef USE_MB - if (my_mbcharlen(cs, c) == 1) -#endif + { + int l; + if ((l= my_mbcharlen(cs, c)) == 1) { if (c == (uchar) NAMES_SEP_CHAR) break; /* Old .frm format can't handle this char */ @@ -695,15 +710,12 @@ int yylex(void *arg, void *yythd) } } #ifdef USE_MB - else + else if (l > 1) { - int l; - if ((l = my_ismbchar(cs, - (const char *)lex->ptr-1, - (const char *)lex->end_of_query)) == 0) - break; lex->ptr += l-1; } + else + break; #endif } if (double_quotes) @@ -886,8 +898,13 @@ int yylex(void *arg, void *yythd) } /* fall true */ case MY_LEX_EOL: - lex->next_state=MY_LEX_END; // Mark for next loop - return(END_OF_INPUT); + if (lex->ptr >= lex->end_of_query) + { + lex->next_state=MY_LEX_END; // Mark for next loop + return(END_OF_INPUT); + } + state=MY_LEX_CHAR; + break; case MY_LEX_END: lex->next_state=MY_LEX_END; return(0); // We found end of input last time diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 81d6b80678d..69ee43d53d1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -48,7 +48,6 @@ extern "C" int gethostname(char *name, int namelen); #endif -char *memdup_mysql(struct st_mysql *mysql, const char*data, int length); static int check_for_max_user_connections(THD *thd, USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); @@ -1420,8 +1419,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #ifndef EMBEDDED_LIBRARY mysql_parse(thd, packet, length); #else - thd->query_rest= (char*)memdup_mysql(thd->mysql, packet, length); - thd->query_rest_length= length; + /* + 'packet' can point inside the query_rest's buffer + so we have to do memmove here + */ + if (thd->query_rest.length() > length) + { + memmove(thd->query_rest.c_ptr(), packet, length); + thd->query_rest.length(length); + } + else + thd->query_rest.copy(length); break; #endif /*EMBEDDED_LIBRARY*/ } @@ -3854,23 +3862,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); - if (!yyparse((void *)thd) && ! thd->is_fatal_error && - /* - If this is not a multiple query, ensure that it has been - successfully parsed until the last character. This is to prevent - against a wrong (too big) length passed to mysql_real_query(), - mysql_prepare()... which can generate garbage characters at the - end. If the query was initially multiple, found_colon will be false - only when we are in the last query; this last query had already - been end-spaces-stripped by alloc_query() in dispatch_command(); as - end spaces are the only thing we accept at the end of a query, and - they have been stripped already, here we can require that nothing - remains after parsing. - */ - (thd->lex->found_colon || - (char*)(thd->lex->ptr) == (thd->query+thd->query_length+1) || - /* yyerror() will show the garbage chars to the user */ - (yyerror("syntax error"), 0))) + if (!yyparse((void *)thd) && ! thd->is_fatal_error) { #ifndef NO_EMBEDDED_ACCESS_CHECKS if (mqh_used && thd->user_connect && diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9be11b6154c..a3c1b5a46eb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -947,15 +947,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) lex->safe_to_cache_query= 0; lex->param_count= 0; - if (yyparse((void *)thd) || thd->is_fatal_error || - /* - Check for wrong (too big) length passed to mysql_prepare() resulting in - garbage at the end of the query. There is a similar check in mysql_parse(). - */ - (!thd->lex->found_colon && - (char*)(thd->lex->ptr) != (thd->query+thd->query_length+1) && - /* yyerror() will show the garbage chars to the user */ - (yyerror("syntax error"), 1)) || send_prepare_results(stmt)) + if (yyparse((void *)thd) || thd->is_fatal_error || send_prepare_results(stmt)) goto yyparse_err; lex_end(lex); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4da2522bd3f..f076e2fe802 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1085,8 +1085,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) DBUG_RETURN(0); } -/* possible TODO: call find_keyword() from sql_lex.cc here */ -static bool require_quotes(const char *name, uint length) +static inline const char *require_quotes(const char *name, uint length) { uint i, d, c; for (i=0; i<length; i+=d) @@ -1094,7 +1093,37 @@ static bool require_quotes(const char *name, uint length) c=((uchar *)name)[i]; d=my_mbcharlen(system_charset_info, c); if (d==1 && !system_charset_info->ident_map[c]) - return 1; + return name+i; + } + return 0; +} + +/* + Looking for char in multibyte string + + SYNOPSIS + look_for_char() + name string for looking at + length length of name + q '\'' or '\"' for looking for + + RETURN VALUES + # pointer to found char in string + 0 string doesn't contain required char +*/ + +static inline const char *look_for_char(const char *name, + uint length, char q) +{ + const char *cur= name; + const char *end= cur+length; + uint symbol_length; + for (; cur<end; cur+= symbol_length) + { + char c= *cur; + symbol_length= my_mbcharlen(system_charset_info, c); + if (symbol_length==1 && c==q) + return cur; } return 0; } @@ -1103,21 +1132,52 @@ void append_identifier(THD *thd, String *packet, const char *name, uint length) { char qtype; + uint part_len; + const char *qplace; if (thd->variables.sql_mode & MODE_ANSI_QUOTES) qtype= '\"'; else qtype= '`'; - if ((thd->options & OPTION_QUOTE_SHOW_CREATE) || - require_quotes(name, length)) + if (is_keyword(name,length)) { - packet->append(&qtype, 1); + packet->append(&qtype, 1, system_charset_info); packet->append(name, length, system_charset_info); - packet->append(&qtype, 1); + packet->append(&qtype, 1, system_charset_info); } else { - packet->append(name, length, system_charset_info); + if (!(qplace= require_quotes(name, length))) + { + if (!(thd->options & OPTION_QUOTE_SHOW_CREATE)) + packet->append(name, length, system_charset_info); + else + { + packet->append(&qtype, 1, system_charset_info); + packet->append(name, length, system_charset_info); + packet->append(&qtype, 1, system_charset_info); + } + } + else + { + packet->shrink(packet->length()+length+2); + packet->append(&qtype, 1, system_charset_info); + if (*qplace != qtype) + qplace= look_for_char(qplace+1,length-(qplace-name)-1,qtype); + while (qplace) + { + if ((part_len= qplace-name)) + { + packet->append(name, part_len, system_charset_info); + length-= part_len; + } + packet->append(qplace, 1, system_charset_info); + name= qplace; + qplace= look_for_char(name+1,length-1,qtype); + } + packet->append(name, length, system_charset_info); + packet->append(&qtype, 1, system_charset_info); + } } } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 093b85b46b7..e76c7902210 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -453,7 +453,7 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) if (!arg_length) // Default argument if (!(arg_length= (uint32) strlen(s))) return FALSE; - if (str_charset->mbmaxlen > 1) + if (cs != str_charset && str_charset->mbmaxlen > 1) { uint32 add_length=arg_length * str_charset->mbmaxlen; if (realloc(str_length+ add_length)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4e66154e2a2..404d2b56e06 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -877,7 +877,12 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, column->field_name); DBUG_RETURN(-1); } - key_part_info->length=(uint8) length; + if (length > file->max_key_part_length()) + { + my_error(ER_WRONG_SUB_KEY,MYF(0)); + DBUG_RETURN(-1); + } + key_part_info->length=(uint16) length; /* Use packed keys for long strings on the first column */ if (!(db_options & HA_OPTION_NO_PACK_KEYS) && (length >= KEY_DEFAULT_PACK_LENGTH && diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index bdeaf5a0b86..0e68fcc016d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2152,13 +2152,13 @@ select_init: SELECT_LEX * sel= lex->current_select; if (sel->set_braces(1)) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } if (sel->linkage == UNION_TYPE && !sel->master_unit()->first_select()->braces) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } /* select in braces, can't contain global parameters */ @@ -2174,13 +2174,13 @@ select_init2: SELECT_LEX * sel= lex->current_select; if (lex->current_select->set_braces(0)) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } if (sel->linkage == UNION_TYPE && sel->master_unit()->first_select()->braces) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } } @@ -2734,7 +2734,7 @@ simple_expr: { if ($1->type() != Item::ROW_ITEM) { - send_error(Lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } $$= new Item_func_interval((Item_row *)$1); @@ -3070,7 +3070,7 @@ in_sum_expr: LEX *lex= Lex; if (lex->current_select->inc_in_sum_expr()) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } } @@ -3241,8 +3241,8 @@ select_derived: if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) - { - send_error(lex->thd, ER_SYNTAX_ERROR); + { + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || @@ -3877,7 +3877,7 @@ opt_insert_update: for a moment */ if (Lex->sql_command != SQLCOM_INSERT) { - send_error(Lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } } @@ -4484,7 +4484,7 @@ param_marker: } else { - yyerror("You have an error in your SQL syntax"); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } } @@ -5527,7 +5527,7 @@ union_list: } if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { - send_error(lex->thd, ER_SYNTAX_ERROR); + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } if (mysql_new_select(lex, 0)) @@ -5627,8 +5627,8 @@ subselect_start: if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) - { - send_error(lex->thd, ER_SYNTAX_ERROR); + { + yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } if (mysql_new_select(Lex, 1)) diff --git a/strings/Makefile.am b/strings/Makefile.am index 61219c8abb9..89f32ac6b40 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -22,19 +22,19 @@ pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X if ASSEMBLER_x86 ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s -CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c +CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c else if ASSEMBLER_sparc32 # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s -CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c +CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c else #no assembler ASRCS = # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile -CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c +CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c endif endif diff --git a/strings/atof.c b/strings/atof.c deleted file mode 100644 index 0e0aa598718..00000000000 --- a/strings/atof.c +++ /dev/null @@ -1,207 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - A quicker atof. About 2-10 times faster than standard atof on sparc. - This don't handle iee-options (NaN...) and the presission :s is a little - less for some high exponential numbers (+-1 at 14th place). - Returns 0.0 if overflow or wrong number. - Must be inited with init_my_atof to handle possibly overflows. -*/ - -#include <my_global.h> -#ifdef USE_MY_ATOF /* Skipp if we don't want it */ -#include <m_ctype.h> -#include <floatingpoint.h> -#include <signal.h> - -/* Read a double. If float is wrong return 0. - float ::= [space]* [sign] {digit}+ decimal-point {digit}+ [exponent] | - [sign] {digit}+ [decimal-point {digit}*] exponent | - [sign] {digit}+ decimal-point [{digit}*] exponent | - [sign] decimal-point {digit}* exponent | - exponent :: = exponent-marker [sign] {digit}+ - exponent-marker ::= E e - */ - - -#define is_exponent_marker(ch) (ch == 'E' || ch == 'e') - -static void my_atof_overflow _A((int sig,int code, struct sigcontext *scp, - char *addr)); -static int parse_sign _A((char **str)); -static void parse_float_number_part _A((char **str,double *number, int *length)); -static void parse_decimal_number_part _A((char **str,double *number)); -static int parse_int_number_part _A((char **str,uint *number)); - -static int volatile overflow,in_my_atof; -static sigfpe_handler_type old_overflow_handler; - -void init_my_atof() -{ - old_overflow_handler = (sigfpe_handler_type) - ieee_handler("get", "overflow", old_overflow_handler); - VOID(ieee_handler("set", "overflow", my_atof_overflow)); - return; -} - -static void my_atof_overflow(sig, code, scp, addr) -int sig; -int code; -struct sigcontext *scp; -char *addr; -{ - if (!in_my_atof) - old_overflow_handler(sig,code,scp,addr); - else - overflow=1; - return; -} - -double my_atof(src) -const char *src; -{ - int sign, exp_sign; /* is number negative (+1) or positive (-1) */ - int length_before_point; - double after_point; /* Number after decimal point and before exp */ - uint exponent; /* Exponent value */ - double exp_log,exp_val; - char *tmp_src; - double result_number; - - tmp_src = (char*) src; - while (isspace(tmp_src[0])) - tmp_src++; /* Skipp pre-space */ - sign = parse_sign(&tmp_src); - overflow=0; - in_my_atof=1; - parse_float_number_part(&tmp_src, &result_number, &length_before_point); - if (*tmp_src == '.') - { - tmp_src++; - parse_decimal_number_part(&tmp_src, &after_point); - result_number += after_point; - } - else if (length_before_point == 0) - { - in_my_atof=0; - return 0.0; - } - if (is_exponent_marker(*tmp_src)) - { - tmp_src++; - exp_sign = parse_sign(&tmp_src); - overflow|=parse_int_number_part(&tmp_src, &exponent); - - exp_log=10.0; exp_val=1.0; - for (;;) - { - if (exponent & 1) - { - exp_val*= exp_log; - exponent--; - } - if (!exponent) - break; - exp_log*=exp_log; - exponent>>=1; - } - if (exp_sign < 0) - result_number*=exp_val; - else - result_number/=exp_val; - } - if (sign > 0) - result_number= -result_number; - - in_my_atof=0; - if (overflow) - return 0.0; - return result_number; -} - - -static int parse_sign(str) -char **str; -{ - if (**str == '-') - { - (*str)++; - return 1; - } - if (**str == '+') - (*str)++; - return -1; -} - - /* Get number with may be separated with ',' */ - -static void parse_float_number_part(str, number, length) -char **str; -double *number; -int *length; -{ - *number = 0; - *length = 0; - - for (;;) - { - while (isdigit(**str)) - { - (*length)++; - *number = (*number * 10) + (**str - '0'); - (*str)++; - } - if (**str != ',') - return; /* Skipp possibly ',' */ - (*str)++; - } -} - -static void parse_decimal_number_part(str, number) -char **str; -double *number; -{ - double exp_log; - - *number = 0; - exp_log=1/10.0; - while (isdigit(**str)) - { - *number+= (**str - '0')*exp_log; - exp_log/=10; - (*str)++; - } -} - - /* Parses int suitably for exponent */ - -static int parse_int_number_part(str, number) -char **str; -uint *number; -{ - *number = 0; - while (isdigit(**str)) - { - if (*number >= ((uint) ~0)/10) - return 1; /* Don't overflow */ - *number = (*number * 10) + **str - '0'; - (*str)++; - } - return 0; -} - -#endif diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 233251e16a8..e4435d1222d 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -684,7 +684,7 @@ noconv: double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), - char *str, uint length, + char *str, uint length, char **end, int *err) { char end_char; @@ -702,12 +702,12 @@ double my_strntod_8bit(CHARSET_INFO *cs __attribute__((unused)), #else if (length == INT_MAX32 || str[length] == 0) #endif - result= strtod(str, end); + result= my_strtod(str, end); else { end_char= str[length]; str[length]= 0; - result= strtod(str, end); + result= my_strtod(str, end); str[length]= end_char; /* Restore end char */ } *err= errno; diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index bb74e0cf56b..ec306d9af35 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -856,7 +856,7 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), if (length >= sizeof(buf)) length= sizeof(buf)-1; end= s+length; - + while ((cnv=cs->cset->mb_wc(cs,&wc,s,end)) > 0) { s+=cnv; @@ -865,9 +865,9 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)), *b++= (char) wc; } *b= 0; - + errno= 0; - res=strtod(buf, endptr); + res=my_strtod(buf, endptr); *err= errno; if (endptr) *endptr=(char*) (*endptr-buf+nptr); diff --git a/strings/strtod.c b/strings/strtod.c new file mode 100644 index 00000000000..ea6acbac6c4 --- /dev/null +++ b/strings/strtod.c @@ -0,0 +1,140 @@ +/* + An alternative implementation of "strtod()" that is both + simplier, and thread-safe. + + From mit-threads as bundled with MySQL 3.22 + + SQL:2003 specifies a number as + +<signed numeric literal> ::= [ <sign> ] <unsigned numeric literal> + +<unsigned numeric literal> ::= + <exact numeric literal> + | <approximate numeric literal> + +<exact numeric literal> ::= + <unsigned integer> [ <period> [ <unsigned integer> ] ] + | <period> <unsigned integer> + +<approximate numeric literal> ::= <mantissa> E <exponent> + +<mantissa> ::= <exact numeric literal> + +<exponent> ::= <signed integer> + + So do we. + + */ + +#include "my_base.h" +#include "m_ctype.h" + +static double scaler10[] = { + 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 +}; +static double scaler1[] = { + 1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 +}; + +// let's use a static array for not to accumulate the error +static double pastpoint[] = { + 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, + 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, + 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29, + 1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39, + 1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45, 1e-46, 1e-47, 1e-48, 1e-49, + 1e-50, 1e-51, 1e-52, 1e-53, 1e-54, 1e-55, 1e-56, 1e-57, 1e-58, 1e-59, +}; + +double my_strtod(const char *str, char **end) +{ + double result= 0.0; + int negative, ndigits; + const char *old_str; + + while (my_isspace(&my_charset_latin1, *str)) + str++; + + if ((negative= (*str == '-')) || *str=='+') + str++; + + old_str= str; + while (my_isdigit (&my_charset_latin1, *str)) + { + result= result*10.0 + (*str - '0'); + str++; + } + ndigits= str-old_str; + + if (*str == '.') + { + int n= 0; + str++; + old_str= str; + while (my_isdigit (&my_charset_latin1, *str)) + { + if (n < sizeof(pastpoint)/sizeof(pastpoint[0])) + { + result+= pastpoint[n] * (*str - '0'); + n++; + } + str++; + } + ndigits+= str-old_str; + if (!ndigits) str--; + } + if (ndigits && (*str=='e' || *str=='E')) + { + int exp= 0; + int neg= 0; + const char *old_str= str++; + + if ((neg= (*str == '-')) || *str == '+') + str++; + + if (!my_isdigit (&my_charset_latin1, *str)) + str= old_str; + else + { + double scaler= 1.0; + while (my_isdigit (&my_charset_latin1, *str)) + { + exp= exp*10 + *str - '0'; + str++; + } + if (exp >= 1000) + { + if (neg) + result= 0.0; + else + result= DBL_MAX; + goto done; + } + while (exp >= 100) + { + scaler*= 1.0e100; + exp-= 100; + } + scaler*= scaler10[exp/10]*scaler1[exp%10]; + if (neg) + result/= scaler; + else + result*= scaler; + } + } + +done: + if (end) + *end = (char *)str; + + if (isinf(result)) + result=DBL_MAX; + + return negative ? -result : result; +} + +double my_atof(const char *nptr) +{ + return (strtod(nptr, 0)); +} + diff --git a/tests/client_test.c b/tests/client_test.c index 0f3698b8a29..2275ef6d9f7 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -8113,6 +8113,84 @@ static void test_parse_error_and_bad_length() } +static void test_bug2247() +{ + MYSQL_STMT *stmt; + MYSQL_RES *res; + int rc; + int i; + const char *create= "CREATE TABLE bug2247(id INT UNIQUE AUTO_INCREMENT)"; + const char *insert= "INSERT INTO bug2247 VALUES (NULL)"; + const char *select= "SELECT id FROM bug2247"; + const char *update= "UPDATE bug2247 SET id=id+10"; + const char *drop= "DROP TABLE IF EXISTS bug2247"; + ulonglong exp_count; + enum { NUM_ROWS= 5 }; + + myheader("test_bug2247"); + + fprintf(stdout, "\nChecking if stmt_affected_rows is not affected by\n" + "mysql_query ... "); + /* create table and insert few rows */ + rc = mysql_query(mysql, drop); + myquery(rc); + + rc= mysql_query(mysql, create); + myquery(rc); + + stmt= mysql_prepare(mysql, insert, strlen(insert)); + mystmt_init(stmt); + for (i= 0; i < NUM_ROWS; ++i) + { + rc= mysql_execute(stmt); + mystmt(stmt, rc); + } + exp_count= mysql_stmt_affected_rows(stmt); + assert(exp_count == 1); + + rc= mysql_query(mysql, select); + myquery(rc); + /* + mysql_store_result overwrites mysql->affected_rows. Check that + mysql_stmt_affected_rows() returns the same value, whereas + mysql_affected_rows() value is correct. + */ + res= mysql_store_result(mysql); + mytest(res); + + assert(mysql_affected_rows(mysql) == NUM_ROWS); + assert(exp_count == mysql_stmt_affected_rows(stmt)); + + rc= mysql_query(mysql, update); + myquery(rc); + assert(mysql_affected_rows(mysql) == NUM_ROWS); + assert(exp_count == mysql_stmt_affected_rows(stmt)); + + mysql_free_result(res); + mysql_stmt_close(stmt); + + /* check that mysql_stmt_store_result modifies mysql_stmt_affected_rows */ + stmt= mysql_prepare(mysql, select, strlen(select)); + mystmt_init(stmt); + + rc= mysql_execute(stmt); + mystmt(stmt, rc); + rc= mysql_stmt_store_result(stmt); + mystmt(stmt, rc); + exp_count= mysql_stmt_affected_rows(stmt); + assert(exp_count == NUM_ROWS); + + rc= mysql_query(mysql, insert); + myquery(rc); + assert(mysql_affected_rows(mysql) == 1); + assert(mysql_stmt_affected_rows(stmt) == exp_count); + + mysql_stmt_close(stmt); + fprintf(stdout, "OK"); +} + + + static void test_subqueries() { MYSQL_STMT *stmt; @@ -8195,7 +8273,9 @@ static void test_distinct() myquery(rc); } - +/* + Test for bug#2248 "mysql_fetch without prior mysql_execute hangs" +*/ static void test_bug2248() { @@ -8502,6 +8582,9 @@ int main(int argc, char **argv) test_bug2248(); /* BUG#2248 */ test_parse_error_and_bad_length(); /* test if bad length param in mysql_prepare() triggers error */ + test_bug2247(); /* test that mysql_stmt_affected_rows() returns + number of rows affected by last prepared + statement execution */ test_subqueries(); /* repeatable subqueries */ test_bad_union(); /* correct setup of UNION */ test_distinct(); /* distinct aggregate functions */ |