diff options
48 files changed, 1189 insertions, 639 deletions
diff --git a/.bzrignore b/.bzrignore index 12930a30dbe..99e6c82316f 100644 --- a/.bzrignore +++ b/.bzrignore @@ -596,3 +596,4 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +scripts/fill_help_tables.sql diff --git a/client/mysql.cc b/client/mysql.cc index 7114d63fda6..41da0113670 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1398,8 +1398,8 @@ int mysql_real_query_for_lazy(const char *buf, int length) if (!mysql_real_query(&mysql,buf,length)) return 0; uint error=put_info(mysql_error(&mysql),INFO_ERROR, mysql_errno(&mysql)); - if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 - || status.batch) + if (mysql_errno(&mysql) != CR_SERVER_GONE_ERROR || retry > 1 || + status.batch) return error; if (reconnect()) return error; @@ -1417,8 +1417,9 @@ int mysql_store_result_for_lazy(MYSQL_RES **result) return 0; } + static int com_server_help(String *buffer __attribute__((unused)), - char *line __attribute__((unused)), char *help_arg) + char *line __attribute__((unused)), char *help_arg) { MYSQL_ROW cur; const char *server_cmd= buffer->ptr(); @@ -1460,22 +1461,23 @@ static int com_server_help(String *buffer __attribute__((unused)), init_pager(); if (cur[1][0] == 'Y') { - tee_fprintf(PAGER, "\nHelp topic \'%s\'\n", cur[0]); + tee_fprintf(PAGER, "Help topic \'%s\'\n", cur[0]); tee_fprintf(PAGER, "%s\n", cur[2]); - tee_fprintf(PAGER, "For help on specific function please type 'help <function>' where function is one of next :\n%s\n", cur[3]); + tee_fprintf(PAGER, "For help on specific function please type 'help <function>'\nwhere function is one of next:\n%s\n", cur[3]); } else { - tee_fprintf(PAGER, "\nName : \'%s\'\n\n", cur[0]); - tee_fprintf(PAGER, "Description : \n%s\n\n", cur[2]); - tee_fprintf(PAGER, "Examples : \n%s\n", cur[3]); + tee_fprintf(PAGER, "Name: \'%s\'\n\n", cur[0]); + tee_fprintf(PAGER, "Description:\n%s\n\n", cur[2]); + if (cur[3]) + tee_fprintf(PAGER, "Examples:\n%s\n", cur[3]); } end_pager(); } else if (num_rows > 1) { - put_info("\nMany help items for your request exist", INFO_INFO); - put_info("For more specific request please type 'help <item>' where item is one of next :", INFO_INFO); + put_info("Many help items for your request exist", INFO_INFO); + put_info("For more specific request please type 'help <item>' where item is one of next:", INFO_INFO); init_pager(); char last_char= '_'; @@ -1506,8 +1508,8 @@ err: } static int -com_help (String *buffer __attribute__((unused)), - char *line __attribute__((unused))) +com_help(String *buffer __attribute__((unused)), + char *line __attribute__((unused))) { reg1 int i; char * help_arg= strchr(line,' '); @@ -1530,13 +1532,9 @@ com_help (String *buffer __attribute__((unused)), tee_fprintf(stdout, "%s\t(\\%c)\t%s\n", commands[i].name, commands[i].cmd_char, commands[i].doc); } - if (connected) - tee_fprintf(stdout, - "\nConnection id: %ld (Can be used with mysqladmin kill)\n\n", - mysql_thread_id(&mysql)); - else - tee_fprintf(stdout, "Not connected! Reconnect with 'connect'!\n\n"); } + if (connected && mysql_get_server_version(&mysql) >= 40100) + put_info("\nFor server side help, type 'help all'\n", INFO_INFO); return 0; } @@ -2417,7 +2415,6 @@ com_use(String *buffer __attribute__((unused)), char *line) } - /* Gets argument from a command on the command line. If get_next_arg is not defined, skips the command and returns the first argument. The diff --git a/cmd-line-utils/libedit/compat.h b/cmd-line-utils/libedit/compat.h index f432ac45dfc..3693a2db809 100644 --- a/cmd-line-utils/libedit/compat.h +++ b/cmd-line-utils/libedit/compat.h @@ -36,4 +36,8 @@ #endif #endif +#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) +#define __attribute__(A) +#endif + #endif diff --git a/cmd-line-utils/libedit/fgetln.c b/cmd-line-utils/libedit/fgetln.c index 9804866147f..4f7416a4c8d 100644 --- a/cmd-line-utils/libedit/fgetln.c +++ b/cmd-line-utils/libedit/fgetln.c @@ -56,7 +56,8 @@ getline (char **lineptr, size_t *n, FILE *stream) if (*n >= new_size) /* Overflowed size_t */ line = NULL; else - line = (char *)*lineptr ? realloc (*lineptr, new_size) : malloc (new_size); + line = (char *) (*lineptr ? (char*) realloc(*lineptr, new_size) : + (char*) malloc(new_size)); if (line) { diff --git a/include/mysql.h b/include/mysql.h index d16563ac7e2..51bffa60294 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -419,6 +419,7 @@ int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid); int STDCALL mysql_ping(MYSQL *mysql); const char * STDCALL mysql_stat(MYSQL *mysql); const char * STDCALL mysql_get_server_info(MYSQL *mysql); +unsigned long STDCALL mysql_get_server_version(MYSQL *mysql); const char * STDCALL mysql_get_client_info(void); const char * STDCALL mysql_get_host_info(MYSQL *mysql); unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 220e9af4357..53c97aff27b 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3402,6 +3402,35 @@ mysql_get_server_info(MYSQL *mysql) } +/* + Get version number for server in a form easy to test on + + SYNOPSIS + mysql_get_server_version() + mysql Connection + + EXAMPLE + 4.1.0-alfa -> 40100 + + NOTES + We will ensure that a newer server always has a bigger number. + + RETURN + Signed number > 323000 +*/ + +ulong STDCALL +mysql_get_server_version(MYSQL *mysql) +{ + uint major, minor, version; + char *pos= mysql->server_version, *end_pos; + major= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; + minor= (uint) strtoul(pos, &end_pos, 10); pos=end_pos+1; + version= (uint) strtoul(pos, &end_pos, 10); + return (ulong) major*10000L+(ulong) (minor*100+version); +} + + const char * STDCALL mysql_get_host_info(MYSQL *mysql) { diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 10d94b09756..cb43d4aa539 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -386,7 +386,7 @@ mysql_init(MYSQL *mysql) } -static void mysql_once_init() +void STDCALL mysql_once_init() { if (!mysql_client_init) { diff --git a/mysql-test/install_test_db.sh b/mysql-test/install_test_db.sh index 990c763efc8..fc3e00d8501 100644 --- a/mysql-test/install_test_db.sh +++ b/mysql-test/install_test_db.sh @@ -66,6 +66,9 @@ c_h="" i_h="" c_u="" i_u="" c_f="" i_f="" c_t="" c_c="" +c_hl="" c_hl="" +c_hc="" c_hc="" +c_clr="" c_clr="" # Check for old tables if test ! -f $mdata/db.frm @@ -207,6 +210,42 @@ then c_c="$c_c comment='Column privileges';" fi +if test ! -f $mdata/help_topic.frm +then + c_hl="$c_hl CREATE TABLE help_topic (" + c_hl="$c_hl help_topic_id int unsigned not null auto_increment," + c_hl="$c_hl name varchar(64) not null," + c_hl="$c_hl description text not null," + c_hl="$c_hl example text not null," + c_hl="$c_hl url varchar(128) not null," + c_hl="$c_hl primary key (help_topic_id)," + c_hl="$c_hl unique index (name)" + c_hl="$c_hl )" + c_hl="$c_hl comment='help topics';" +fi + +if test ! -f $mdata/help_category.frm +then + c_clr="$c_clr CREATE TABLE help_category (" + c_clr="$c_clr help_category_id smallint unsigned not null auto_increment," + c_clr="$c_clr name varchar(64) not null," + c_clr="$c_clr url varchar(128) not null," + c_clr="$c_clr primary key (help_category_id)," + c_clr="$c_clr unique index (name)" + c_clr="$c_clr )" + c_clr="$c_clr comment='help topics-categories relation';" +fi + +if test ! -f $mdata/help_relation.frm +then + c_hc="$c_hc CREATE TABLE help_relation (" + c_hc="$c_hc help_topic_id int unsigned not null references help_topic," + c_hc="$c_hc help_category_id smallint unsigned not null references help_category," + c_hc="$c_hc primary key (help_category_id, help_topic_id)," + c_hc="$c_hc )" + c_hc="$c_hc comment='categories of help topics';" +fi + mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \ --basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $EXTRA_ARG" echo "running $mysqld_boot" @@ -227,6 +266,10 @@ $i_f $c_t $c_c + +$c_hl +$c_hc +$c_clr END_OF_DATA then exit 0 diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index 3e9091462d8..b7243ac5d0b 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -3,6 +3,9 @@ Tables_in_mysql columns_priv db func +help_category +help_relation +help_topic host tables_priv user @@ -15,6 +18,9 @@ Tables_in_mysql columns_priv db func +help_category +help_relation +help_topic host tables_priv user @@ -27,6 +33,9 @@ Tables_in_mysql columns_priv db func +help_category +help_relation +help_topic host tables_priv user diff --git a/mysql-test/r/help.result b/mysql-test/r/help.result new file mode 100644 index 00000000000..4da4a84d4ad --- /dev/null +++ b/mysql-test/r/help.result @@ -0,0 +1,123 @@ +truncate mysql.help_topic; +truncate mysql.help_category; +truncate mysql.help_relation; +insert into mysql.help_topic(name,description,example)values('impossible_function_1','description of \n impossible_function1','example of \n impossible_function1'); +SELECT @topic1_id:=LAST_INSERT_ID(); +@topic1_id:=LAST_INSERT_ID() +1 +insert into mysql.help_topic(name,description,example)values('impossible_function_2','description of \n impossible_function2','example of \n impossible_function2'); +SELECT @topic2_id:=LAST_INSERT_ID(); +@topic2_id:=LAST_INSERT_ID() +2 +insert into mysql.help_topic(name,description,example)values('impossible_function_3','description of \n impossible_function3','example of \n impossible_function3'); +SELECT @topic3_id:=LAST_INSERT_ID(); +@topic3_id:=LAST_INSERT_ID() +3 +insert into mysql.help_category(name)values('impossible_category_1'); +SELECT @category1_id:=LAST_INSERT_ID(); +@category1_id:=LAST_INSERT_ID() +1 +insert into mysql.help_category(name)values('impossible_category_2'); +SELECT @category2_id:=LAST_INSERT_ID(); +@category2_id:=LAST_INSERT_ID() +2 +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category1_id,@topic1_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category1_id,@topic2_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category2_id,@topic2_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category2_id,@topic3_id); +help 'function_of_my_dream'; +Name Category +impossible_category_1 Y +impossible_category_2 Y +help '%possible_f%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +help 'impossible_func%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +help 'impossible_category%'; +Name Category +impossible_category_1 Y +impossible_category_2 Y +help 'impossible_%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_category_1 Y +impossible_category_2 Y +help '%function_2'; +Name Category Description Example +impossible_function_2 N description of + impossible_function2 example of + impossible_function2 +help '%category_2'; +Name Category Description Example +impossible_category_2 Y impossible_function_2 +impossible_function_3 + +help 'impossible_function_1'; +Name Category Description Example +impossible_function_1 N description of + impossible_function1 example of + impossible_function1 +help 'impossible_category_1'; +Name Category Description Example +impossible_category_1 Y impossible_function_1 +impossible_function_2 + +alter table mysql.help_topic type=innodb; +alter table mysql.help_category type=innodb; +alter table mysql.help_relation type=innodb; +help 'function_of_my_dream'; +Name Category +impossible_category_1 Y +impossible_category_2 Y +help '%ble_f%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +help 'impossible_func%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +help 'impossible_category%'; +Name Category +impossible_category_1 Y +impossible_category_2 Y +help 'impossible_%'; +Name Category +impossible_function_1 N +impossible_function_2 N +impossible_function_3 N +impossible_category_1 Y +impossible_category_2 Y +help '%function_2'; +Name Category Description Example +impossible_function_2 N description of + impossible_function2 example of + impossible_function2 +help '%category_2'; +Name Category Description Example +impossible_category_2 Y impossible_function_2 +impossible_function_3 + +help 'impossible_function_1'; +Name Category Description Example +impossible_function_1 N description of + impossible_function1 example of + impossible_function1 +help 'impossible_category_1'; +Name Category Description Example +impossible_category_1 Y impossible_function_1 +impossible_function_2 + +alter table mysql.help_topic type=myisam; +alter table mysql.help_category type=myisam; +alter table mysql.help_relation type=myisam; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 23610be36c4..c0914e23992 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -364,3 +364,8 @@ explain select * from t1 use index() where c=1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where drop table t1,t2; +CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) TYPE=MyISAM; +This version of MySQL doesn't yet support 'RTREE INDEX' +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 19f1ac2b4d7..8215977ea39 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -85,7 +85,7 @@ CREATE INDEX test3 on t1 ( medium ) ; DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); -insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303 101010','','','','3',3,3); +insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree"); insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0); diff --git a/mysql-test/t/help.test b/mysql-test/t/help.test new file mode 100644 index 00000000000..c36b670c6b3 --- /dev/null +++ b/mysql-test/t/help.test @@ -0,0 +1,50 @@ +-- source include/have_innodb.inc + +truncate mysql.help_topic; +truncate mysql.help_category; +truncate mysql.help_relation; + +insert into mysql.help_topic(name,description,example)values('impossible_function_1','description of \n impossible_function1','example of \n impossible_function1'); +SELECT @topic1_id:=LAST_INSERT_ID(); +insert into mysql.help_topic(name,description,example)values('impossible_function_2','description of \n impossible_function2','example of \n impossible_function2'); +SELECT @topic2_id:=LAST_INSERT_ID(); +insert into mysql.help_topic(name,description,example)values('impossible_function_3','description of \n impossible_function3','example of \n impossible_function3'); +SELECT @topic3_id:=LAST_INSERT_ID(); + +insert into mysql.help_category(name)values('impossible_category_1'); +SELECT @category1_id:=LAST_INSERT_ID(); +insert into mysql.help_category(name)values('impossible_category_2'); +SELECT @category2_id:=LAST_INSERT_ID(); + +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category1_id,@topic1_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category1_id,@topic2_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category2_id,@topic2_id); +insert into mysql.help_relation(help_category_id,help_topic_id)values(@category2_id,@topic3_id); + +help 'function_of_my_dream'; +help '%possible_f%'; +help 'impossible_func%'; +help 'impossible_category%'; +help 'impossible_%'; +help '%function_2'; +help '%category_2'; +help 'impossible_function_1'; +help 'impossible_category_1'; + +alter table mysql.help_topic type=innodb; +alter table mysql.help_category type=innodb; +alter table mysql.help_relation type=innodb; + +help 'function_of_my_dream'; +help '%ble_f%'; +help 'impossible_func%'; +help 'impossible_category%'; +help 'impossible_%'; +help '%function_2'; +help '%category_2'; +help 'impossible_function_1'; +help 'impossible_category_1'; + +alter table mysql.help_topic type=myisam; +alter table mysql.help_category type=myisam; +alter table mysql.help_relation type=myisam; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index ed08b1cbacb..3cce93840e0 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -352,3 +352,12 @@ explain select * from t1 force index (a) where a=0 or a=2; explain select * from t1 where c=1; explain select * from t1 use index() where c=1; drop table t1,t2; + +# +# Test RTREE index +# +--error 1235 +CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) TYPE=MyISAM; +# INSERT INTO t1 VALUES (1,1),(1,1); +# DELETE FROM rt WHERE a<1; +DROP TABLE IF EXISTS t1; diff --git a/mysql-test/t/type_ranges.test b/mysql-test/t/type_ranges.test index 53bfb063b2c..767012d0b34 100644 --- a/mysql-test/t/type_ranges.test +++ b/mysql-test/t/type_ranges.test @@ -55,7 +55,7 @@ DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); -insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303 101010','','','','3',3,3); +insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); insert into t1 values (0,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,-4294967295,NULL,0,0,0,-4294967295,-4294967295,-4294967295,'-4294967295',0,"one,two,tree"); insert into t1 values (0,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,4294967295,NULL,0,0,0,4294967295,4294967295,4294967295,'4294967295',0,0); diff --git a/mysys/charset.c b/mysys/charset.c index 2105877d928..1145a989958 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -324,7 +324,7 @@ CHARSET_INFO *system_charset_info = &my_charset_latin1; #define MY_ADD_CHARSET(x) all_charsets[(x)->number]=(x) -static my_bool init_compiled_charsets(myf flags __attribute__((unused))) +static my_bool init_compiled_charsets(myf flags __attribute__((unused))) { CHARSET_INFO *cs; diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index e287930ff06..abef0096e28 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -103,7 +103,8 @@ int my_symlink(const char *content, const char *linkname, myf MyFlags) #define BUFF_LEN FN_LEN #endif -int my_realpath(char *to, const char *filename, myf MyFlags) +int my_realpath(char *to, const char *filename, + myf MyFlags __attribute__((unused))) { #if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) int result=0; diff --git a/scripts/fill_help_tables.sh b/scripts/fill_help_tables.sh index f6b16a3b434..da6b8ec80ef 100644 --- a/scripts/fill_help_tables.sh +++ b/scripts/fill_help_tables.sh @@ -111,12 +111,12 @@ sub flush_all $example= prepare_example($example); if ($func_name ne "" && $text ne "" && !($func_name =~ /[abcdefghikjlmnopqrstuvwxyz]/)){ - print "INSERT INTO function (name,description,example) VALUES ("; + print "INSERT INTO help_topic (name,description,example) VALUES ("; print "'$func_name',"; print "'$text',"; print "'$example'"; print ");\n"; - print "INSERT INTO function_category (cat_id,func_id) VALUES (\@cur_category,LAST_INSERT_ID());\n"; + print "INSERT INTO help_relation (help_category_id,help_topic_id) VALUES (\@cur_category,LAST_INSERT_ID());\n"; } $func_name= ""; @@ -131,50 +131,43 @@ sub new_category $category= prepare_text($category); - print "INSERT INTO function_category_name (name) VALUES (\'$category\');\n"; - print "SELECT \@cur_category:=LAST_INSERT_ID();\n"; + print "INSERT INTO help_category (name) VALUES (\'$category\');\n"; + print "SET \@cur_category=LAST_INSERT_ID();\n"; } -print "INSERT INTO db (Host,DB,User,Select_priv) VALUES ('%','mysql_help','','Y');\n"; -print "CREATE DATABASE mysql_help;\n"; +#print "INSERT INTO db (Host,DB,User,Select_priv) VALUES ('%','mysql_help','','Y');\n"; +#print "CREATE DATABASE mysql_help;\n"; -print "USE mysql_help;\n"; +print "USE mysql;\n"; -print "DROP TABLE IF EXISTS function;\n"; -print "CREATE TABLE function ("; -print " func_id int unsigned not null auto_increment,"; +print "DROP TABLE IF EXISTS help_topic;\n"; +print "CREATE TABLE help_topic ("; +print " help_topic_id int unsigned not null auto_increment,"; print " name varchar(64) not null,"; -print " url varchar(128) not null,"; print " description text not null,"; print " example text not null,"; -print " min_args tinyint not null,"; -print " max_args tinyint,"; -print " date_created datetime not null,"; -print " last_modified timestamp not null,"; -print " primary key (func_id)"; +print " url varchar(128) not null,"; +print " primary key (help_topic_id),"; +print " uniuqe index(name)"; print ") type=myisam;\n\n"; -print "DROP TABLE IF EXISTS function_category_name;\n"; -print "CREATE TABLE function_category_name ("; -print " cat_id smallint unsigned not null auto_increment,"; -print " name varchar(64) not null,"; -print " url varchar(128) not null,"; -print " date_created datetime not null,"; -print " last_modified timestamp not null,"; -print " primary key (cat_id)"; +print "DROP TABLE IF EXISTS help_category;\n"; +print "CREATE TABLE help_category ("; +print " help_category_id smallint unsigned not null auto_increment,"; +print " name varchar(64) not null,"; +print " url varchar(128) not null,"; +print " primary key (help_category_id),"; +print " unique index (name)"; print ") type=myisam;\n\n"; -print "DROP TABLE IF EXISTS function_category;\n"; -print "CREATE TABLE function_category ("; -print " cat_id smallint unsigned not null references function_category_name,"; -print " func_id int unsigned not null references function,"; -print " primary key (cat_id, func_id)"; +print "DROP TABLE IF EXISTS help_relation;\n"; +print "CREATE TABLE help_relation ("; +print" help_topic_id int unsigned not null references help_topic,"; +print" help_category_id smallint unsigned not null references help_category,"; +print" primary key (help_category_id, help_topic_id),"; print ") type=myisam;\n\n"; -print "DELETE FROM function_category_name;\n"; -print "DELETE FROM function_category;\n"; -print "DELETE FROM function;\n"; -print "SELECT \@cur_category:=null;\n\n"; +print "SET \@cur_category=null;\n\n"; my $in_section_6_3= 0; @@ -239,8 +232,8 @@ for(<>) } -print "DELETE function_category_name "; -print "FROM function_category_name "; -print "LEFT JOIN function_category ON function_category.cat_id=function_category_name.cat_id "; -print "WHERE function_category.cat_id is null;" +print "DELETE help_category "; +print "FROM help_category "; +print "LEFT JOIN help_relation ON help_category.help_category_id=help_relation.help_category_id "; +print "WHERE help_relation.help_category_id is null;" diff --git a/sql/field.cc b/sql/field.cc index 7b21f179660..3b3320bb2f4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4226,7 +4226,8 @@ uint Field_varstring::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } -void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,imagetype type) +void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs, + imagetype type) { length-= HA_KEY_BLOB_LENGTH; uint f_length=uint2korr(ptr); @@ -4478,7 +4479,7 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr, /* The following is used only when comparing a key */ void Field_blob::get_key_image(char *buff,uint length, - CHARSET_INFO *cs,imagetype type) + CHARSET_INFO *cs, imagetype type) { length-= HA_KEY_BLOB_LENGTH; uint32 blob_length= get_length(ptr); @@ -4522,7 +4523,8 @@ void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs) } -void Field_geom::get_key_image(char *buff,uint length,CHARSET_INFO *cs, imagetype type) +void Field_geom::get_key_image(char *buff,uint length,CHARSET_INFO *cs, + imagetype type) { length-=HA_KEY_BLOB_LENGTH; ulong blob_length=get_length(ptr); diff --git a/sql/filesort.cc b/sql/filesort.cc index 8bf9c648e82..fcee26278d1 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer, uint maxbuffer,IO_CACHE *tempfile, IO_CACHE *outfile); static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count); -static uint sortlength(SORT_FIELD *sortorder,uint length); +static uint sortlength(SORT_FIELD *sortorder, uint s_length, + bool *multi_byte_charset); /* Creates a set of pointers that can be used to read the rows @@ -75,19 +76,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, uchar **sort_keys; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; - CHARSET_INFO *charset= &my_charset_bin; + bool multi_byte_charset; DBUG_ENTER("filesort"); DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length);); #ifdef SKIP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif - // BAR TODO: this is not absolutely correct, but OK for now - for (i=0;i<table->fields;i++) - if (!table->field[i]->binary()) - charset=table->field[i]->charset(); - // /BAR TODO - outfile= table->io_cache; my_b_clear(&tempfile); my_b_clear(&buffpek_pointers); @@ -96,7 +91,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, error= 1; bzero((char*) ¶m,sizeof(param)); param.ref_length= table->file->ref_length; - param.sort_length=sortlength(sortorder,s_length)+ param.ref_length; + param.sort_length= (sortlength(sortorder,s_length, &multi_byte_charset)+ + param.ref_length); param.max_rows= max_rows; if (select && select->quick) @@ -123,7 +119,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, if (param.sort_length == param.ref_length && records > param.max_rows) records=param.max_rows; /* purecov: inspected */ - if (use_strnxfrm(charset) && + if (multi_byte_charset && !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME)))) goto err; @@ -493,28 +489,19 @@ static void make_sortkey(register SORTPARAM *param, diff=0; /* purecov: inspected */ length=sort_field->length; } - if (use_strnxfrm(cs)) + if (sort_field->need_strxnfrm) { - if (item->binary()) - { - if (res->ptr() != (char*) to) - memcpy(to,res->ptr(),length); - bzero((char*) to+length,diff); - } - else - { - char *from=(char*) res->ptr(); - if ((unsigned char *)from == to) - { - set_if_smaller(length,sort_field->length); - memcpy(param->tmp_buffer,from,length); - from=param->tmp_buffer; - } - uint tmp_length=my_strnxfrm(cs,to,sort_field->length, - (unsigned char *) from, length); - if (tmp_length < sort_field->length) - bzero((char*) to+tmp_length,sort_field->length-tmp_length); - } + char *from=(char*) res->ptr(); + if ((unsigned char *)from == to) + { + set_if_smaller(length,sort_field->length); + memcpy(param->tmp_buffer,from,length); + from=param->tmp_buffer; + } + uint tmp_length=my_strnxfrm(cs,to,sort_field->length, + (unsigned char *) from, length); + if (tmp_length < sort_field->length) + bzero((char*) to+tmp_length,sort_field->length-tmp_length); } else { @@ -907,17 +894,36 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer, } /* merge_index */ - /* Calculate length of sort key */ +/* + Calculate length of sort key + + SYNOPSIS + sortlength() + sortorder Order of items to sort + uint s_length Number of items to sort + multi_byte_charset (out) + Set to 1 if we are using multi-byte charset + (In which case we have to use strxnfrm()) + + NOTES + sortorder->length is updated for each sort item + sortorder->need_strxnfrm is set 1 if we have to use strxnfrm + + RETURN + Total length of sort buffer in bytes +*/ static uint -sortlength(SORT_FIELD *sortorder, uint s_length) +sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) { reg2 uint length; THD *thd= current_thd; + *multi_byte_charset= 0; length=0; for (; s_length-- ; sortorder++) { + sortorder->need_strxnfrm= 0; if (sortorder->field) { if (sortorder->field->type() == FIELD_TYPE_BLOB) @@ -929,7 +935,11 @@ sortlength(SORT_FIELD *sortorder, uint s_length) { CHARSET_INFO *cs=sortorder->field->charset(); if (use_strnxfrm(cs)) + { + sortorder->need_strxnfrm= 1; + *multi_byte_charset= 1; sortorder->length= sortorder->length*cs->strxfrm_multiply; + } } } if (sortorder->field->maybe_null()) @@ -944,7 +954,11 @@ sortlength(SORT_FIELD *sortorder, uint s_length) { CHARSET_INFO *cs=sortorder->item->charset(); if (use_strnxfrm(cs)) + { sortorder->length= sortorder->length*cs->strxfrm_multiply; + sortorder->need_strxnfrm= 1; + *multi_byte_charset= 1; + } } break; case INT_RESULT: diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7bec9983a20..b189f34912c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -125,8 +125,10 @@ void Item_bool_func2::fix_length_and_dec() } } set_cmp_func(); + binary_cmp= args[0]->binary() || args[1]->binary(); } + int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) { owner= item; @@ -165,7 +167,7 @@ int Arg_comparator::compare_string() if ((res2= (*b)->val_str(&owner->tmp_value2))) { owner->null_value= 0; - return owner->binary() ? stringcmp(res1,res2) : sortcmp(res1,res2); + return owner->binary_cmp ? stringcmp(res1,res2) : sortcmp(res1,res2); } } owner->null_value= 1; @@ -179,7 +181,7 @@ int Arg_comparator::compare_e_string() res2= (*b)->val_str(&owner->tmp_value2); if (!res1 || !res2) return test(res1 == res2); - return (owner->binary() ? test(stringcmp(res1, res2) == 0) : + return (owner->binary_cmp ? test(stringcmp(res1, res2) == 0) : test(sortcmp(res1, res2) == 0)); } @@ -274,6 +276,7 @@ bool Item_in_optimizer::preallocate_row() return (!(cache= Item_cache::get_cache(ROW_RESULT))); } + bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, Item ** ref) { @@ -281,8 +284,12 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, return 1; if (args[0]->maybe_null) maybe_null=1; + /* + TODO: Check if following is right + (set_charset set type of result, not how compare should be used) + */ if (args[0]->binary()) - set_charset(&my_charset_bin); + set_charset(&my_charset_bin); with_sum_func= args[0]->with_sum_func; used_tables_cache= args[0]->used_tables(); const_item_cache= args[0]->const_item(); @@ -395,7 +402,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value= binary() ? stringcmp(a,b) : sortcmp(a,b); + int value= binary_cmp ? stringcmp(a,b) : sortcmp(a,b); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -659,7 +666,7 @@ Item_func_if::fix_length_and_dec() else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT) { cached_result_type = STRING_RESULT; - set_charset( (args[1]->binary() || args[2]->binary()) ? + set_charset((args[1]->binary() || args[2]->binary()) ? &my_charset_bin : args[1]->charset()); } else @@ -802,7 +809,7 @@ Item *Item_func_case::find_item(String *str) } if ((tmp=args[i]->val_str(str))) // If not null { - if (first_expr->binary() || args[i]->binary()) + if (first_expr_is_binary || args[i]->binary()) { if (stringcmp(tmp,first_expr_str)==0) return args[i+1]; @@ -912,6 +919,7 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) used_tables_cache|=(first_expr)->used_tables(); const_item_cache&= (first_expr)->const_item(); with_sum_func= with_sum_func || (first_expr)->with_sum_func; + first_expr_is_binary= first_expr->binary(); } if (else_expr) { @@ -1193,7 +1201,7 @@ byte *in_double::get_value(Item *item) return (byte*) &tmp; } -cmp_item* cmp_item::get_comparator (Item *item) +cmp_item* cmp_item::get_comparator(Item *item) { switch (item->result_type()) { case STRING_RESULT: @@ -1368,7 +1376,7 @@ void Item_func_in::fix_length_and_dec() } else { - in_item= cmp_item:: get_comparator(item); + in_item= cmp_item::get_comparator(item); } maybe_null= item->maybe_null; max_length= 1; @@ -1690,13 +1698,6 @@ longlong Item_func_isnotnull::val_int() } -void Item_func_like::fix_length_and_dec() -{ - decimals= 0; - max_length= 1; - // cmp_type=STRING_RESULT; // For quick select -} - longlong Item_func_like::val_int() { String* res = args[0]->val_str(&tmp_value1); @@ -1740,6 +1741,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const return OPTIMIZE_NONE; } + bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { if (Item_bool_func2::fix_fields(thd, tlist, ref)) @@ -1800,8 +1802,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length= 1; decimals= 0; - if (args[0]->binary() || args[1]->binary()) - set_charset(&my_charset_bin); + binary_cmp= (args[0]->binary() || args[1]->binary()); used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); const_item_cache=args[0]->const_item() && args[1]->const_item(); @@ -1817,7 +1818,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } int error; if ((error=regcomp(&preg,res->c_ptr(), - binary() ? REG_EXTENDED | REG_NOSUB : + binary_cmp ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE, res->charset()))) { @@ -1834,6 +1835,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; } + longlong Item_func_regex::val_int() { char buff[MAX_FIELD_WIDTH]; @@ -1865,7 +1867,7 @@ longlong Item_func_regex::val_int() regex_compiled=0; } if (regcomp(&preg,res2->c_ptr(), - binary() ? REG_EXTENDED | REG_NOSUB : + binary_cmp ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE, res->charset())) @@ -1915,7 +1917,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) *splm1 = pattern_len; - if (binary()) + if (binary_cmp) { int i; for (i = pattern_len - 2; i >= 0; i--) @@ -2018,7 +2020,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() for (i = bmBc; i < end; i++) *i = pattern_len; - if (binary()) + if (binary_cmp) { for (j = 0; j < plm1; j++) bmBc[(uint) (uchar) pattern[j]] = plm1 - j; @@ -2049,7 +2051,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const const int tlmpl= text_len - pattern_len; /* Searching */ - if (binary()) + if (binary_cmp) { while (j <= tlmpl) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 97e69b5dfe6..8534150acd7 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -112,6 +112,8 @@ class Item_bool_func2 :public Item_int_func protected: Arg_comparator cmp; String tmp_value1,tmp_value2; + bool binary_cmp; + public: Item_bool_func2(Item *a,Item *b): Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} @@ -125,6 +127,7 @@ public: bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } void print(String *str) { Item_func::print_op(str); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } + virtual bool binary() const { return binary_cmp; } static Item_bool_func2* eq_creator(Item *a, Item *b); static Item_bool_func2* ne_creator(Item *a, Item *b); @@ -156,7 +159,7 @@ public: class Item_func_eq :public Item_bool_rowready_func2 { public: - Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }; + Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; longlong val_int(); enum Functype functype() const { return EQ_FUNC; } enum Functype rev_functype() const { return EQ_FUNC; } @@ -180,7 +183,7 @@ public: class Item_func_ge :public Item_bool_rowready_func2 { public: - Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }; + Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; longlong val_int(); enum Functype functype() const { return GE_FUNC; } enum Functype rev_functype() const { return LE_FUNC; } @@ -192,7 +195,7 @@ public: class Item_func_gt :public Item_bool_rowready_func2 { public: - Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }; + Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; longlong val_int(); enum Functype functype() const { return GT_FUNC; } enum Functype rev_functype() const { return LT_FUNC; } @@ -204,7 +207,7 @@ public: class Item_func_le :public Item_bool_rowready_func2 { public: - Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }; + Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}; longlong val_int(); enum Functype functype() const { return LE_FUNC; } enum Functype rev_functype() const { return GE_FUNC; } @@ -216,7 +219,7 @@ public: class Item_func_lt :public Item_bool_rowready_func2 { public: - Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { } + Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {} longlong val_int(); enum Functype functype() const { return LT_FUNC; } enum Functype rev_functype() const { return GT_FUNC; } @@ -228,7 +231,7 @@ public: class Item_func_ne :public Item_bool_rowready_func2 { public: - Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { } + Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {} longlong val_int(); enum Functype functype() const { return NE_FUNC; } cond_result eq_cmp_result() const { return COND_FALSE; } @@ -257,7 +260,11 @@ class Item_func_strcmp :public Item_bool_func2 public: Item_func_strcmp(Item *a,Item *b) :Item_bool_func2(a,b) {} longlong val_int(); - void fix_length_and_dec() { max_length=2; } + void fix_length_and_dec() + { + max_length=2; + binary_cmp= args[0]->binary() || args[1]->binary(); + } optimize_type select_optimize() const { return OPTIMIZE_NONE; } const char *func_name() const { return "strcmp"; } }; @@ -280,7 +287,9 @@ class Item_func_ifnull :public Item_func { enum Item_result cached_result_type; public: - Item_func_ifnull(Item *a,Item *b) :Item_func(a,b) { } + Item_func_ifnull(Item *a,Item *b) + :Item_func(a,b), cached_result_type(INT_RESULT) + {} double val(); longlong val_int(); String *val_str(String *str); @@ -294,7 +303,9 @@ class Item_func_if :public Item_func { enum Item_result cached_result_type; public: - Item_func_if(Item *a,Item *b,Item *c) :Item_func(a,b,c) { } + Item_func_if(Item *a,Item *b,Item *c) + :Item_func(a,b,c), cached_result_type(INT_RESULT) + {} double val(); longlong val_int(); String *val_str(String *str); @@ -313,7 +324,9 @@ class Item_func_nullif :public Item_bool_func2 { enum Item_result cached_result_type; public: - Item_func_nullif(Item *a,Item *b) :Item_bool_func2(a,b) { } + Item_func_nullif(Item *a,Item *b) + :Item_bool_func2(a,b), cached_result_type(INT_RESULT) + {} double val(); longlong val_int(); String *val_str(String *str); @@ -327,7 +340,9 @@ class Item_func_coalesce :public Item_func { enum Item_result cached_result_type; public: - Item_func_coalesce(List<Item> &list) :Item_func(list) {} + Item_func_coalesce(List<Item> &list) + :Item_func(list),cached_result_type(INT_RESULT) + {} double val(); longlong val_int(); String *val_str(String *); @@ -341,9 +356,12 @@ class Item_func_case :public Item_func Item * first_expr, *else_expr; enum Item_result cached_result_type; String tmp_value; + bool first_expr_is_binary; public: - Item_func_case(List<Item> &list, Item *first_expr_, Item *else_expr_) - :Item_func(list), first_expr(first_expr_), else_expr(else_expr_) {} + Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg) + :Item_func(list), first_expr(first_expr_arg), else_expr(else_expr_arg), + cached_result_type(INT_RESULT) + {} double val(); longlong val_int(); String *val_str(String *); @@ -723,7 +741,6 @@ public: optimize_type select_optimize() const; cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } - void fix_length_and_dec(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); }; @@ -737,6 +754,7 @@ class Item_func_regex :public Item_bool_func bool regex_compiled; bool regex_is_const; String prev_regexp; + bool binary_cmp; public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), regex_compiled(0),regex_is_const(0) {} diff --git a/sql/item_func.cc b/sql/item_func.cc index 788961a954d..2c8b9e97fb3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -80,6 +80,7 @@ Item_func::Item_func(List<Item> &list): str_value.charset If this is a string function, set this to the character set for the first argument. + If any argument is binary, this is set to binary If for any item any of the defaults are wrong, then this can be fixed in the fix_length_and_dec() function that is called @@ -96,6 +97,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item **arg,**arg_end; char buff[STACK_BUFF_ALLOC]; // Max argument in function + used_tables_cache=0; const_item_cache=1; @@ -103,6 +105,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; // Fatal error if flag is set! if (arg_count) { // Print purify happy + CHARSET_INFO *charset= 0; /* Set return character set to first argument if we are returning a string. @@ -115,15 +118,21 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if ((*arg)->maybe_null) maybe_null=1; if ((*arg)->binary()) - set_charset(&my_charset_bin); + charset= &my_charset_bin; + else if (!charset && (*arg)->result_type() == STRING_RESULT) + charset= (*arg)->charset(); with_sum_func= with_sum_func || (*arg)->with_sum_func; used_tables_cache|=(*arg)->used_tables(); const_item_cache&= (*arg)->const_item(); } + /* + We must set charset here as fix_length_and_dec() may want to change + charset + */ + if (charset && result_type() == STRING_RESULT) + set_charset(charset); } fix_length_and_dec(); - if (result_type() == STRING_RESULT) - set_charset((*args)->charset()); fixed= 1; return 0; } @@ -847,6 +856,8 @@ void Item_func_min_max::fix_length_and_dec() if (args[i]->binary()) set_charset(&my_charset_bin); } + if (cmp_type == STRING_RESULT) + str_cmp_function= binary() ? stringcmp : sortcmp; } @@ -891,7 +902,7 @@ String *Item_func_min_max::val_str(String *str) res2= args[i]->val_str(res == str ? &tmp_value : str); if (res2) { - int cmp=binary() ? stringcmp(res,res2) : sortcmp(res,res2); + int cmp= (*str_cmp_function)(res,res2); if ((cmp_sign < 0 ? cmp : -cmp) < 0) res=res2; } @@ -994,7 +1005,6 @@ longlong Item_func_locate::val_int() { String *a=args[0]->val_str(&value1); String *b=args[1]->val_str(&value2); - bool binary_str = args[0]->binary() || args[1]->binary(); if (!a || !b) { null_value=1; @@ -1012,7 +1022,7 @@ longlong Item_func_locate::val_int() if (use_mb(a->charset())) { start0=start; - if (!binary_str) + if (!binary_cmp) start=a->charpos(start); } #endif @@ -1022,7 +1032,7 @@ longlong Item_func_locate::val_int() if (!b->length()) // Found empty string at start return (longlong) (start+1); #ifdef USE_MB - if (use_mb(a->charset()) && !binary_str) + if (use_mb(a->charset()) && !binary_cmp) { const char *ptr=a->ptr()+start; const char *search=b->ptr(); @@ -1049,7 +1059,7 @@ longlong Item_func_locate::val_int() return 0; } #endif /* USE_MB */ - return (longlong) (binary() ? a->strstr(*b,start) : + return (longlong) (binary_cmp ? a->strstr(*b,start) : (a->strstr_case(*b,start)))+1; } @@ -1662,7 +1672,7 @@ longlong Item_master_pos_wait::val_int() { THD* thd = current_thd; String *log_name = args[0]->val_str(&value); - int event_count; + int event_count= 0; null_value=0; if (thd->slave_thread || !log_name || !log_name->length()) diff --git a/sql/item_func.h b/sql/item_func.h index 7fec2467ff1..68804b83d26 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -524,9 +524,10 @@ class Item_func_min_max :public Item_func Item_result cmp_type; String tmp_value; int cmp_sign; + int (*str_cmp_function)(const String *x,const String *y); public: Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list), - cmp_sign(cmp_sign_arg) {} + cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg) {} double val(); longlong val_int(); String *val_str(String *); @@ -590,12 +591,17 @@ public: class Item_func_locate :public Item_int_func { String value1,value2; + bool binary_cmp; public: Item_func_locate(Item *a,Item *b) :Item_int_func(a,b) {} Item_func_locate(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} const char *func_name() const { return "locate"; } longlong val_int(); - void fix_length_and_dec() { maybe_null=0; max_length=11; } + void fix_length_and_dec() + { + maybe_null=0; max_length=11; + binary_cmp = args[0]->binary() || args[1]->binary(); + } }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d5d8e6eeb1d..308e6e89284 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -701,7 +701,7 @@ String *Item_func_replace::val_str(String *str) #ifdef USE_MB const char *ptr,*end,*strend,*search,*search_end; register uint32 l; - bool binary_str; + bool binary_cmp; #endif null_value=0; @@ -713,7 +713,7 @@ String *Item_func_replace::val_str(String *str) goto null; #ifdef USE_MB - binary_str = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset())); + binary_cmp = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset())); #endif if (res2->length() == 0) @@ -723,7 +723,7 @@ String *Item_func_replace::val_str(String *str) return res; #else offset=0; - if (binary_str && (offset=res->strstr(*res2)) < 0) + if (binary_cmp && (offset=res->strstr(*res2)) < 0) return res; #endif if (!(res3=args[2]->val_str(&tmp_value2))) @@ -732,7 +732,7 @@ String *Item_func_replace::val_str(String *str) to_length= res3->length(); #ifdef USE_MB - if (!binary_str) + if (!binary_cmp) { search=res2->ptr(); search_end=search+from_length; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 9c9f00af78b..c2db50345d1 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -187,7 +187,10 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) else if (hybrid_type == REAL_RESULT) max_length=float_length(decimals); else + { + str_cmp_function= binary() ? stringcmp : sortcmp; max_length=item->max_length; + } decimals=item->decimals; maybe_null=item->maybe_null; unsigned_flag=item->unsigned_flag; @@ -434,8 +437,7 @@ bool Item_sum_min::add() { String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && - (null_value || - (binary() ? stringcmp(&value,result) : sortcmp(&value,result)) > 0)) + (null_value || (*str_cmp_function)(&value,result) > 0)) { value.copy(*result); null_value=0; @@ -481,8 +483,7 @@ bool Item_sum_max::add() { String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && - (null_value || - (binary() & MY_CS_BINSORT ? stringcmp(&value,result) : sortcmp(&value,result)) < 0)) + (null_value || (*str_cmp_function)(&value,result) < 0)) { value.copy(*result); null_value=0; @@ -757,8 +758,7 @@ Item_sum_hybrid::min_max_update_str_field(int offset) result_field->ptr-=offset; if (result_field->is_null() || - (cmp_sign * (binary() ? stringcmp(res_str,&tmp_value) : - sortcmp(res_str,&tmp_value)) < 0)) + (cmp_sign * (*str_cmp_function)(res_str,&tmp_value)) < 0) result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); else { // Use old value diff --git a/sql/item_sum.h b/sql/item_sum.h index be92f37f2a7..db8bded9946 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -369,9 +369,11 @@ class Item_sum_hybrid :public Item_sum enum_field_types hybrid_field_type; int cmp_sign; table_map used_table_cache; + int (*str_cmp_function)(const String *x,const String *y); public: - Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign), + Item_sum_hybrid(Item *item_par,int sign) + :Item_sum(item_par), hybrid_type(INT_RESULT), cmp_sign(sign), used_table_cache(~(table_map) 0) {} Item_sum_hybrid(THD *thd, Item_sum_hybrid &item): diff --git a/sql/key.cc b/sql/key.cc index 875a89a146f..38ab596e213 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -194,7 +194,8 @@ int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length) { if (my_strnncoll(key_part->field->charset(), (const uchar*) key, length, - (const uchar*) table->record[0]+key_part->offset,length)) + (const uchar*) table->record[0]+key_part->offset, + length)) return 1; } else if (memcmp(key,table->record[0]+key_part->offset,length)) diff --git a/sql/lex.h b/sql/lex.h index 67b2ba85dc0..3fa7dd97250 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -180,7 +180,7 @@ static SYMBOL symbols[] = { { "HANDLER", SYM(HANDLER_SYM),0,0}, { "HASH", SYM(HASH_SYM),0,0}, { "HEAP", SYM(HEAP_SYM),0,0}, - { "HELP", SYM(HELP),0,0}, + { "HELP", SYM(HELP_SYM),0,0}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0}, { "HOUR", SYM(HOUR_SYM),0,0}, { "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3336a7fa642..dd5bee2eed5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -854,7 +854,7 @@ int rename_file_ext(const char * from,const char * to,const char * ext); bool check_db_name(char *db); bool check_column_name(const char *name); bool check_table_name(const char *name, uint length); -char *get_field(MEM_ROOT *mem,TABLE *table,uint fieldnr); +char *get_field(MEM_ROOT *mem, Field *field); int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr); /* from hostname.cc */ diff --git a/sql/password.c b/sql/password.c index 37040c20683..5ed05ae6c0e 100644 --- a/sql/password.c +++ b/sql/password.c @@ -147,9 +147,9 @@ double rnd(struct rand_struct *rand_st) none */ -void create_random_string(int length,struct rand_struct *rand_st,char* target) +void create_random_string(int length,struct rand_struct *rand_st,char *target) { - char* end=target+length; + char *end=target+length; /* Use pointer arithmetics as it is faster way to do so. */ for (; target<end ; target++) *target= (char) (rnd(rand_st)*94+33); @@ -171,7 +171,7 @@ void create_random_string(int length,struct rand_struct *rand_st,char* target) none */ -void password_crypt(const char* from,char* to, const char* password,int length) +void password_crypt(const char *from,char *to, const char *password,int length) { const char *from_end=from+length; @@ -252,7 +252,7 @@ void password_hash_stage1(char *to, const char *password) none */ -void password_hash_stage2(char *to,const char *salt) +void password_hash_stage2(char *to, const char *salt) { SHA1_CONTEXT context; sha1_reset(&context); @@ -326,7 +326,7 @@ void make_scrambled_password(char *to,const char *password, void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt) { - unsigned char* password_end=password+SCRAMBLE41_LENGTH; + unsigned char *password_end=password+SCRAMBLE41_LENGTH; *res=salt; res++; @@ -356,14 +356,14 @@ void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt) !0 for invalid password */ -my_bool validate_password(const char* password, const char* message, - ulong* salt) +my_bool validate_password(const char *password, const char *message, + ulong *salt) { char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */ char tmpsalt[8]; /* Temporary value to convert salt to string form */ ulong salt_candidate[6]; /* Computed candidate salt */ - ulong* sc=salt_candidate; /* we need to be able to increment */ - ulong* salt_end; + ulong *sc=salt_candidate; /* we need to be able to increment */ + ulong *salt_end; /* Now we shall get stage1 encrypted password in buffer*/ password_crypt(password,buffer,message,SCRAMBLE41_LENGTH); @@ -414,7 +414,7 @@ int get_password_length(my_bool force_old_scramble) !0 password version char for newer passwords */ -char get_password_version(const char* password) +char get_password_version(const char *password) { if (password==NULL) return 0; if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR; @@ -536,46 +536,47 @@ void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version) !0 password version char for newer passwords */ -void get_hash_and_password(ulong* salt, uint8 pversion, char* hash, unsigned char* bin_password) +void get_hash_and_password(ulong *salt, uint8 pversion, char *hash, + unsigned char *bin_password) { int t; ulong* salt_end; ulong val; SHA1_CONTEXT context; - unsigned char* bp; /* Binary password loop pointer */ - if (pversion) /* New password version assumed */ + if (pversion) /* New password version assumed */ { salt_end=salt+5; sprintf(hash,"%04x",(unsigned short)salt[0]); - while (salt<salt_end) /* Iterate over these elements*/ + while (salt<salt_end) { val=*(++salt); for (t=3; t>=0; t--) { bin_password[t]= (char) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ + val>>=8; /* Scroll 8 bits to get next part*/ } - bin_password+=4; /* Get to next 4 chars*/ + bin_password+=4; /* Get to next 4 chars*/ } } else { + unsigned char *bp= bin_password; /* Binary password loop pointer */ + /* Use zero starting hash as an indication of old password */ hash[0]=0; salt_end=salt+2; - bp=bin_password; /* Encode salt using SHA1 here */ sha1_reset(&context); - while (salt<salt_end) /* Iterate over these elements*/ + while (salt<salt_end) /* Iterate over these elements*/ { - val=*salt; + val= *salt; for (t=3;t>=0;t--) { bp[t]= (uchar) (val & 255); - val>>=8; /* Scroll 8 bits to get next part*/ + val>>=8; /* Scroll 8 bits to get next part*/ } - bp+=4; /* Get to next 4 chars*/ + bp+= 4; /* Get to next 4 chars*/ salt++; } /* Use 8 bytes of binary password for hash */ @@ -599,7 +600,7 @@ void get_hash_and_password(ulong* salt, uint8 pversion, char* hash, unsigned cha */ -void create_key_from_old_password(const char* passwd, char* key) +void create_key_from_old_password(const char *passwd, char *key) { char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */ ulong salt[6]; /* Salt (large for safety) */ @@ -633,7 +634,7 @@ char *scramble(char *to,const char *message,const char *password, struct rand_struct rand_st; ulong hash_pass[2],hash_message[2]; char message_buffer[9]; /* Real message buffer */ - char* msg=message_buffer; + char *msg=message_buffer; /* We use special message buffer now as new server can provide longer hash */ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 36bf93c8c34..40dddaad08e 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -148,8 +148,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) while (!(read_record_info.read_record(&read_record_info))) { ACL_HOST host; - update_hostname(&host.host,get_field(&mem, table,0)); - host.db= get_field(&mem, table,1); + update_hostname(&host.host,get_field(&mem, table->field[0])); + host.db= get_field(&mem, table->field[1]); host.access= get_access(table,2); host.access= fix_rights_for_db(host.access); host.sort= get_sort(2,host.host.hostname,host.db); @@ -190,9 +190,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) { ACL_USER user; uint length=0; - update_hostname(&user.host,get_field(&mem, table,0)); - user.user=get_field(&mem, table,1); - user.password=get_field(&mem, table,2); + update_hostname(&user.host,get_field(&mem, table->field[0])); + user.user=get_field(&mem, table->field[1]); + user.password=get_field(&mem, table->field[2]); if (user.password && (length=(uint) strlen(user.password)) == 8 && protocol_version == PROTOCOL_VERSION) { @@ -220,7 +220,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) (uint) strlen(user.host.hostname) : 0); if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ { - char *ssl_type=get_field(&mem, table, 24); + char *ssl_type=get_field(&mem, table->field[24]); if (!ssl_type) user.ssl_type=SSL_TYPE_NONE; else if (!strcmp(ssl_type, "ANY")) @@ -230,15 +230,15 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) else /* !strcmp(ssl_type, "SPECIFIED") */ user.ssl_type=SSL_TYPE_SPECIFIED; - user.ssl_cipher= get_field(&mem, table, 25); - user.x509_issuer= get_field(&mem, table, 26); - user.x509_subject= get_field(&mem, table, 27); + user.ssl_cipher= get_field(&mem, table->field[25]); + user.x509_issuer= get_field(&mem, table->field[26]); + user.x509_subject= get_field(&mem, table->field[27]); - char *ptr = get_field(&mem, table, 28); + char *ptr = get_field(&mem, table->field[28]); user.user_resource.questions=atoi(ptr); - ptr = get_field(&mem, table, 29); + ptr = get_field(&mem, table->field[29]); user.user_resource.updates=atoi(ptr); - ptr = get_field(&mem, table, 30); + ptr = get_field(&mem, table->field[30]); user.user_resource.connections=atoi(ptr); if (user.user_resource.questions || user.user_resource.updates || user.user_resource.connections) @@ -277,14 +277,14 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) while (!(read_record_info.read_record(&read_record_info))) { ACL_DB db; - update_hostname(&db.host,get_field(&mem, table,0)); - db.db=get_field(&mem, table,1); + update_hostname(&db.host,get_field(&mem, table->field[0])); + db.db=get_field(&mem, table->field[1]); if (!db.db) { sql_print_error("Found an entry in the 'db' table with empty database name; Skipped"); continue; } - db.user=get_field(&mem, table,2); + db.user=get_field(&mem, table->field[2]); db.access=get_access(table,3); db.access=fix_rights_for_db(db.access); db.sort=get_sort(3,db.host.hostname,db.db,db.user); @@ -457,8 +457,9 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) return 0; } + /* - Prepare crypted scramble to be sent to the client + Prepare crypted scramble to be sent to the client */ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) @@ -469,18 +470,17 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble); thd->scramble[SCRAMBLE41_LENGTH]=0; /* Get binary form, First 4 bytes of prepared scramble is salt */ - get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble,(unsigned char*)bin_password); + get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble, + (unsigned char*) bin_password); /* Store "*" as identifier for old passwords */ if (!acl_user->pversion) prepared_scramble[0]='*'; /* Finally encrypt password to get prepared scramble */ - password_crypt(thd->scramble,prepared_scramble+4,bin_password,SCRAMBLE41_LENGTH); + password_crypt(thd->scramble, prepared_scramble+4, bin_password, + SCRAMBLE41_LENGTH); } - - - /* Get master privilges for user (priviliges for all tables). Required before connecting to MySQL @@ -493,7 +493,7 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, const char *password,const char *message,char **priv_user, - bool old_ver, USER_RESOURCES *mqh,char* prepared_scramble, + bool old_ver, USER_RESOURCES *mqh, char *prepared_scramble, uint *cur_priv_version,ACL_USER** hint_user) { ulong user_access=NO_ACCESS; @@ -572,10 +572,11 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, if (!check_scramble(password,message,acl_user->salt, (my_bool) old_ver)) password_correct=1; - else /* Password incorrect */ - /* At the first stage - prepare scramble */ - if (!stage) - prepare_scramble(thd,acl_user,prepared_scramble); + else if (!stage) /* Here if password incorrect */ + { + /* At the first stage - prepare scramble */ + prepare_scramble(thd,acl_user,prepared_scramble); + } } } } @@ -1645,12 +1646,12 @@ public: { byte key[MAX_KEY_LENGTH]; - host = get_field(&memex,form,0); - db = get_field(&memex,form,1); - user = get_field(&memex,form,2); + host = get_field(&memex,form->field[0]); + db = get_field(&memex,form->field[1]); + user = get_field(&memex,form->field[2]); if (!user) user=(char*) ""; - tname = get_field(&memex,form,3); + tname = get_field(&memex,form->field[3]); if (!host || !db || !tname) { /* Wrong table row; Ignore it */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 97c92ff2b8f..d3a049a11da 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1481,6 +1481,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) } else { + DBUG_ASSERT(thd->lock == 0); // You must lock everything at once if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK) if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1))) table= 0; @@ -1512,6 +1513,11 @@ int open_and_lock_tables(THD *thd,TABLE_LIST *tables) thd Thread handler tables Tables to lock + NOTES + You can't call lock_tables twice, as this would break the dead-lock-free + handling thr_lock gives us. You most always get all needed locks at + once. + RETURN VALUES 0 ok -1 Error @@ -1525,6 +1531,7 @@ int lock_tables(THD *thd,TABLE_LIST *tables) if (!thd->locked_tables) { + DBUG_ASSERT(thd->lock == 0); // You must lock everything at once uint count=0; for (table = tables ; table ; table=table->next) count++; @@ -1676,28 +1683,31 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, return field; } -// Special Field pointer for find_field_in_tables returning -const Field *not_found_field= (Field*) 0x1; + /* Find field in table list. SYNOPSIS find_field_in_tables() - thd - pointer to current thread structure - item - field item that should be found - tables - tables for scaning - where - table where field found will be returned via this parameter - report_error - if FALSE then do not report error if item not found and - return not_found_field; + thd Pointer to current thread structure + item Field item that should be found + tables Tables for scaning + where Table where field found will be returned via + this parameter + report_error If FALSE then do not report error if item not found + and return not_found_field RETURN VALUES - 0 - field is not found or field is not unique, error message is - reported - not_found_field - function was called with report_error == FALSE and - field if not found, no error message reported + 0 Field is not found or field is not unique- error + message is reported + not_found_field Function was called with report_error == FALSE and + field was not found. no error message reported. found field */ +// Special Field pointer for find_field_in_tables returning +const Field *not_found_field= (Field*) 0x1; + Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, TABLE_LIST **where, bool report_error) @@ -1802,8 +1812,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } -// Special Item pointer for find_item_in_list returning -const Item **not_found_item= (const Item**) 0x1; /* Find Item in list of items (find_field_in_tables analog) @@ -1813,24 +1821,29 @@ const Item **not_found_item= (const Item**) 0x1; SYNOPSIS find_item_in_list() - find - item to find - items - list of items - counter - to return number of found item + find Item to find + items List of items + counter To return number of found item report_error - REPORT_ALL_ERRORS - report errors, return 0 if error - REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0 - IGNORE_ERRORS - do not report errors, return 0 if error + REPORT_ALL_ERRORS report errors, return 0 if error + REPORT_EXCEPT_NOT_FOUND Do not report 'not found' error and + return not_found_item, report other errors, + return 0 + IGNORE_ERRORS Do not report errors, return 0 if error RETURN VALUES - 0 - item is not found or item is not unique, error message is - reported - not_found_item - function was called with report_error == - REPORT_EXCEPT_NOT_FOUND and item if not found, no error - message reported + 0 Item is not found or item is not unique, + error message is reported + not_found_item Function was called with + report_error == REPORT_EXCEPT_NOT_FOUND and + item was not found. No error message was reported found field - */ +// Special Item pointer for find_item_in_list returning +const Item **not_found_item= (const Item**) 0x1; + + Item ** find_item_in_list(Item *find, List<Item> &items, uint *counter, find_item_error_report_type report_error) @@ -1970,6 +1983,9 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Remap table numbers if INSERT ... SELECT Check also that the 'used keys' and 'ignored keys' exists and set up the table structure accordingly + + This has to be called for all tables that are used by items, as otherwise + table->map is not set and all Item_field will be regarded as const items. */ bool setup_tables(TABLE_LIST *tables) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 9a4ce1b81a4..90fd61ebeb7 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -857,6 +857,7 @@ end: DBUG_VOID_RETURN; } + /* Check if the query is in the cache. If it was cached, send it to the user. @@ -867,8 +868,6 @@ end: -1 The query was cached but we didn't have rights to use it. No error is sent to the client yet. */ - - int Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) diff --git a/sql/sql_class.h b/sql/sql_class.h index 2d492b19a2b..ccbd7a194f2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -882,8 +882,9 @@ typedef struct st_sort_field { Field *field; /* Field to sort */ Item *item; /* Item if not sorting fields */ uint length; /* Length of sort field */ - my_bool reverse; /* if descending sort */ Item_result result_type; /* Type of item */ + bool reverse; /* if descending sort */ + bool need_strxnfrm; /* If we have to use strxnfrm() */ } SORT_FIELD; @@ -898,7 +899,8 @@ typedef struct st_sort_buffer { /* Structure for db & table in sql_yacc */ -class Table_ident :public Sql_alloc { +class Table_ident :public Sql_alloc +{ public: LEX_STRING db; LEX_STRING table; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index d1a232c35b6..1db2f5b9fb8 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -61,7 +61,8 @@ extern const char *any_db; // Special symbol for check_access */ -int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, + TABLE_LIST *org_table_list) { SELECT_LEX *sl= unit->first_select(); List<Item> item_list; @@ -85,6 +86,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) if ((is_union || is_subsel) && unit->create_total_list(thd, lex, &tables, 1)) DBUG_RETURN(-1); + /* + We have to do access checks here as this code is executed before any + sql command is started to execute. + */ if (tables) res= check_table_access(thd,SELECT_ACL, tables); else @@ -173,10 +178,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) res= 1; else { - t->real_name=table->real_name; - t->table=table; + org_table_list->real_name=table->real_name; + org_table_list->table=table; table->derived_select_number= sl->select_number; - table->tmp_table=TMP_TABLE; + table->tmp_table= TMP_TABLE; if (lex->describe) { // to fix a problem in EXPLAIN @@ -185,8 +190,11 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) } else unit->exclude(); - t->db= (char *)""; - t->derived=(SELECT_LEX *) 1; // just in case ... + org_table_list->db= (char *)""; +#ifndef DBUG_OFF + /* Try to catch errors if this is accessed */ + org_table_list->derived=(SELECT_LEX_UNIT *) 1; +#endif table->file->info(HA_STATUS_VARIABLE); } } @@ -196,6 +204,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) free_tmp_table(thd, table); else { + /* Add new temporary table to list of open derived tables */ table->next= thd->derived_tables; thd->derived_tables= table; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index e4c44428242..24ea2e9734e 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -15,288 +15,294 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mysql_priv.h" -#include "sql_select.h" // For select_describe -#include "sql_acl.h" -/*************************************************************************** -** Get help on string -***************************************************************************/ +struct st_find_field +{ + const char *table_name, *field_name; + Field *field; +}; -#define help_charset &my_charset_latin1 +/* Used fields */ + +static struct st_find_field init_used_fields[]= +{ + { "help_topic", "name", 0}, + { "help_topic","description", 0}, + { "help_topic","example", 0}, + { "help_topic", "help_topic_id", 0}, + { "help_category","name", 0}, + { "help_category","help_category_id", 0}, + { "help_relation","help_topic_id", 0}, + { "help_relation","help_category_id", 0} +}; + +enum enum_used_fields +{ + help_topic_name=0, help_topic_description, help_topic_example, + help_topic_help_topic_id, + help_category_name, help_category_help_category_id, + help_relation_help_topic_id, help_relation_help_category_id +}; -MI_INFO *open_help_file(THD *thd, const char *name) +/* + Fill local used field structure with pointer to fields */ + +static bool init_fields(THD *thd, TABLE_LIST *tables, + struct st_find_field *find_field, + uint count) { - char path[FN_REFLEN]; - (void) sprintf(path,"%s/mysql_help/%s",mysql_data_home,name); - MI_INFO *res= 0; - if (!(res= mi_open(path,O_RDONLY,HA_OPEN_WAIT_IF_LOCKED))) + for (; count-- ; find_field++) { - send_error(thd,ER_CORRUPT_HELP_DB); - return 0; + TABLE_LIST *not_used; + /* We have to use 'new' here as field will be re_linked on free */ + Item_field *field= new Item_field("mysql", find_field->table_name, + find_field->field_name); + if (!(find_field->field= find_field_in_tables(thd, field, tables, + ¬_used, + TRUE))) + return 1; } - mi_extra(res,HA_EXTRA_WAIT_LOCK,0); - return res; + return 0; } -#define size_hf_func_id 4 /* func_id int unsigned, */ -#define size_hf_name 64 /* name varchar(64), */ -#define size_hf_url 128 /* url varchar(128), */ -#define size_hf_description sizeof(char*) /* description text, */ -#define size_hf_example sizeof(char*) /* example text, */ -#define size_hf_min_args 16 /* min_args tinyint, */ -#define size_hf_max_args 16 /* max_args tinyint, */ -#define size_hf_date_created 8 /* date_created datetime, */ -#define size_hf_last_modified 8 /* last_modified timestamp, */ - -#define offset_hf_func_id 1 -#define offset_hf_name (offset_hf_func_id+size_hf_func_id) -#define offset_hf_url (offset_hf_name+size_hf_name) -#define offset_hf_description (offset_hf_url+size_hf_url) -#define offset_hf_example (offset_hf_description+size_hf_description) -#define offset_hf_min_args (offset_hf_example+size_hf_example) -#define offset_hf_max_args (offset_hf_min_args+size_hf_min_args) -#define offset_hf_date_created (offset_hf_max_args+size_hf_max_args) -#define offset_hf_last_modified (offset_hf_date_created+size_hf_date_created) - -#define HELP_LEAF_SIZE (offset_hf_last_modified+size_hf_last_modified) - -class help_leaf{ -public: - char record[HELP_LEAF_SIZE]; - - inline const char *get_name() - { - return &record[offset_hf_name]; - } - inline const char *get_description() - { - return *((char**)&record[199/*offset_hf_description*/]); - } - - inline const char *get_example() - { - return *((char**)&record[209/*offset_hf_example*/]); - } - - void prepare_fields() - { - const char *name= get_name(); - const char *c= name + size_hf_name - 1; - while (*c==' ') c--; - int len= c-name+1; - ((char*)name)[len]= '\0'; - } -}; +#define help_charset &my_charset_latin1 -int search_functions(MI_INFO *file_leafs, const char *mask, - List<String> *names, - String **name, String **description, String **example) +/* + Look for topics by mask + + SYNOPSIS + search_topics() + thd Thread handler + topics Table of topic + select Function to test for if matching help topic. + Normally 'help_topic.name like 'bit%' + pfname Pointer to Field structure for field "name" + names List of founded topic's names (out) + name Name of founded topic (out), + Only set if founded exactly one topic) + description Description of founded topic (out) + Only set if founded exactly one topic. + example Example for founded topic (out) + Only if founded exactly one topic. + RETURN VALUES + # number of topics founded +*/ + +int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_field, + SQL_SELECT *select, List<char> *names, + char **name, char **description, char **example) { DBUG_ENTER("search_functions"); int count= 0; - - if (mi_scan_init(file_leafs)) - DBUG_RETURN(-1); - - help_leaf leaf; - - while (!mi_scan(file_leafs,(byte*)&leaf)) + + READ_RECORD read_record_info; + init_read_record(&read_record_info, thd, topics, select,1,0); + while (!read_record_info.read_record(&read_record_info)) { - leaf.prepare_fields(); - - const char *lname= leaf.get_name(); - if (wild_case_compare(help_charset,lname,mask)) + if (!select->cond->val_int()) // Dosn't match like continue; - count++; - if (count>2) + char *lname= get_field(&thd->mem_root, find_field[help_topic_name].field); + count++; + if (count > 2) { - String *s= new String(lname,help_charset); - if (!s->copy()) - names->push_back(s); + names->push_back(lname); } - else if (count==1) + else if (count == 1) { - *description= new String(leaf.get_description(),help_charset); - *example= new String(leaf.get_example(),help_charset); - *name= new String(lname,help_charset); - (*description)->copy(); - (*example)->copy(); - (*name)->copy(); + *description= get_field(&thd->mem_root, + find_field[help_topic_description].field); + *example= get_field(&thd->mem_root, + find_field[help_topic_example].field); + *name= lname; } else { names->push_back(*name); - delete *description; - delete *example; + names->push_back(lname); *name= 0; *description= 0; *example= 0; - - String *s= new String(lname,help_charset); - if (!s->copy()) - names->push_back(s); } } - + end_read_record(&read_record_info); DBUG_RETURN(count); } -#define size_hc_cat_id 2 /* cat_id smallint, */ -#define size_hc_name 64 /* name varchar(64), */ -#define size_hc_url 128 /* url varchar(128), */ -#define size_hc_date_created 8 /* date_created datetime, */ -#define size_hc_last_modified 8 /* last_modified timestamp, */ - -#define offset_hc_cat_id 0 -#define offset_hc_name (offset_hc_cat_id+size_hc_cat_id) -#define offset_hc_url (offset_hc_name+size_hc_name) -#define offset_hc_date_created (offset_hc_url+size_hc_url) -#define offset_hc_last_modified (offset_hc_date_created+size_hc_date_created) - -#define HELP_CATEGORY_SIZE (offset_hc_last_modified+size_hc_last_modified) - -class help_category{ -public: - char record[HELP_CATEGORY_SIZE]; - - inline int16 get_cat_id() - { - return sint2korr(&record[offset_hc_cat_id]); - } - - inline const char *get_name() - { - return &record[offset_hc_name]; - } - - void prepare_fields() - { - const char *name= get_name(); - const char *c= name + size_hc_name - 1; - while (*c==' ') c--; - int len= c-name+1; - ((char*)name)[len]= '\0'; - } -}; - -int search_categories(THD *thd, - const char *mask, List<String> *names, int16 *res_id) +/* + Look for categories by mask + + SYNOPSIS + search_categories() + thd THD for init_read_record + categories Table of categories + select Function to test for if matching help topic. + Normally 'help_topic.name like 'bit%' + names List of founded topic's names (out) + res_id Primary index of founded category (only if + founded exactly one category) + + RETURN VALUES + # Number of categories founded +*/ + +int search_categories(THD *thd, TABLE *categories, + struct st_find_field *find_fields, + SQL_SELECT *select, List<char> *names, int16 *res_id) { + Field *pfname= find_fields[help_category_name].field; DBUG_ENTER("search_categories"); int count= 0; - - MI_INFO *file_categories= 0; - if (!(file_categories= open_help_file(thd,"function_category_name"))) - DBUG_RETURN(-1); - - if (mi_scan_init(file_categories)) + + READ_RECORD read_record_info; + init_read_record(&read_record_info, thd, categories, select,1,0); + while (!read_record_info.read_record(&read_record_info)) { - mi_close(file_categories); - DBUG_RETURN(-1); + if (select && !select->cond->val_int()) + continue; + char *lname= get_field(&thd->mem_root,pfname); + if (++count == 1 && res_id) + { + Field *pcat_id= find_fields[help_category_help_category_id].field; + *res_id= (int16) pcat_id->val_int(); + } + names->push_back(lname); } + end_read_record(&read_record_info); + + DBUG_RETURN(count); +} - help_category category; +/* + Send to client rows in format: + column1 : <name> + column2 : <is_it_category> - while (!mi_scan(file_categories,(byte*)&category)) - { - category.prepare_fields(); + SYNOPSIS + send_variant_2_list() + protocol Protocol for sending + names List of names + cat Value of the column <is_it_category> - const char *lname= category.get_name(); - if (mask && wild_case_compare(help_charset,lname,mask)) - continue; - count++; + RETURN VALUES + -1 Writing fail + 0 Data was successefully send +*/ - if (count==1 && res_id) - *res_id= category.get_cat_id(); - - String *s= new String(lname,help_charset); - if (!s->copy()) - names->push_back(s); - } - - mi_close(file_categories); - DBUG_RETURN(count); -} - -int send_variant_2_list(Protocol *protocol, List<String> *names, - my_bool is_category) +int send_variant_2_list(Protocol *protocol, List<char> *names, + const char *cat) { DBUG_ENTER("send_names"); - - List_iterator<String> it(*names); - String *cur_name; - while ((cur_name = it++)) + + List_iterator<char> it(*names); + const char *cur_name; + while ((cur_name= it++)) { protocol->prepare_for_resend(); - protocol->store(cur_name->ptr()); - protocol->store(is_category ? "Y" : "N"); + protocol->store(cur_name); + protocol->store(cat); if (protocol->write()) DBUG_RETURN(-1); } DBUG_RETURN(0); } -#define size_hcn_cat_id 2 /* cat_id smallint, */ -#define size_hcn_func_id 4 /* func_id int, */ - -#define offset_hcn_cat_id 1 -#define offset_hcn_func_id (offset_hcn_cat_id+size_hcn_cat_id) - -#define HELP_CATEGORY_NAME_SIZE (offset_hcn_func_id + size_hcn_func_id) -class help_category_leaf{ -public: - char record[HELP_CATEGORY_NAME_SIZE]; +/* + Look for all topics of category - inline int16 get_cat_id() - { - return sint2korr(&record[offset_hcn_cat_id]); - } + SYNOPSIS + get_all_topics_for_category() + thd Thread handler + topics Table of topics + relations Table of m:m relation "topic/category" + cat_id Primary index looked for category + res List of founded topic's names (out) - inline int get_func_id() - { - return sint3korr(&record[offset_hcn_func_id]); - } -}; + RETURN VALUES + -1 corrupt database + 0 succesefull +*/ -int get_all_names_for_category(THD *thd,MI_INFO *file_leafs, - int16 cat_id, List<String> *res) +int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations, + struct st_find_field *find_fields, + int16 cat_id, List<char> *res) { - DBUG_ENTER("get_all_names_for_category"); - - MI_INFO *file_names_categories= 0; - if (!(file_names_categories= open_help_file(thd,"function_category"))) - DBUG_RETURN(1); - - help_category_leaf cat_leaf; - help_leaf leaf; - int key_res= mi_rkey(file_names_categories, (byte*)&cat_leaf, 0, - (const byte*)&cat_id,2,HA_READ_KEY_EXACT); - - while (!key_res && cat_leaf.get_cat_id()==cat_id) + char buff[8]; // Max int length + DBUG_ENTER("get_all_topics_for_category"); + + int iindex_topic, iindex_relations; + Field *rtopic_id, *rcat_id; + + if ((iindex_topic= find_type((char*) "PRIMARY", + &topics->keynames, 1+2)-1)<0 || + (iindex_relations= find_type((char*) "PRIMARY", + &relations->keynames, 1+2)-1)<0) { - int leaf_id= cat_leaf.get_func_id(); - - if (!mi_rkey(file_leafs, (byte*)&leaf, 0, - (const byte*)&leaf_id,4,HA_READ_KEY_EXACT)) - { - leaf.prepare_fields(); - String *s= new String(leaf.get_name(),help_charset); - if (!s->copy()) - res->push_back(s); - } - - key_res= mi_rnext(file_names_categories, (byte*)&cat_leaf, 0); + send_error(thd,ER_CORRUPT_HELP_DB); + DBUG_RETURN(-1); + } + rtopic_id= find_fields[help_relation_help_topic_id].field; + rcat_id= find_fields[help_relation_help_category_id].field; + + topics->file->index_init(iindex_topic); + relations->file->index_init(iindex_relations); + + rcat_id->store((longlong) cat_id); + rcat_id->get_key_image(buff, rcat_id->pack_length(), help_charset, + Field::itRAW); + int key_res= relations->file->index_read(relations->record[0], + buff, rcat_id->pack_length(), + HA_READ_KEY_EXACT); + + for ( ; !key_res && cat_id == (int16) rcat_id->val_int() ; + key_res= relations->file->index_next(relations->record[0])) + { + char topic_id_buff[8]; + longlong topic_id= rtopic_id->val_int(); + Field *field= find_fields[help_topic_help_topic_id].field; + field->store((longlong) topic_id); + field->get_key_image(topic_id_buff, field->pack_length(), help_charset, + Field::itRAW); + + if (!topics->file->index_read(topics->record[0], topic_id_buff, + field->pack_length(), + HA_READ_KEY_EXACT)) + res->push_back(get_field(&thd->mem_root, + find_fields[help_topic_name].field)); } - - mi_close(file_names_categories); - DBUG_RETURN(0); } + +/* + Send to client answer for help request + + SYNOPSIS + send_answer_1() + protocol - protocol for sending + s1 - value of column "Name" + s2 - value of column "Category" + s3 - value of column "Description" + s4 - value of column "Example" + + IMPLEMENTATION + Format used: + +----------+---------+------------+------------+ + |Name: |Category |Description |Example | + +----------+---------+------------+------------+ + |String(64)|String(1)|String(1000)|String(1000)| + +----------+---------+------------+------------+ + with exactly one row! + + RETURN VALUES + 1 Writing of head failed + -1 Writing of row failed + 0 Successeful send +*/ + int send_answer_1(Protocol *protocol, const char *s1, const char *s2, const char *s3, const char *s4) { @@ -306,10 +312,10 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2, field_list.push_back(new Item_empty_string("Category",1)); field_list.push_back(new Item_empty_string("Description",1000)); field_list.push_back(new Item_empty_string("Example",1000)); - + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - + protocol->prepare_for_resend(); protocol->store(s1); protocol->store(s2); @@ -317,11 +323,28 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2, protocol->store(s4); if (protocol->write()) DBUG_RETURN(-1); - DBUG_RETURN(0); } +/* + Send to client help header + + SYNOPSIS + send_header_2() + protocol - protocol for sending + + IMPLEMENTATION + +----------+---------+ + |Name: |Category | + +----------+---------+ + |String(64)|String(1)| + +----------+---------+ + + RETURN VALUES + result of protocol->send_fields +*/ + int send_header_2(Protocol *protocol) { DBUG_ENTER("send_header2"); @@ -332,79 +355,165 @@ int send_header_2(Protocol *protocol) } +/* + Server-side function 'help' + + SYNOPSIS + mysqld_help() + thd Thread handler + + RETURN VALUES + 0 Success + 1 Error and send_error already commited + -1 error && send_error should be issued (normal case) +*/ + int mysqld_help(THD *thd, const char *mask) { Protocol *protocol= thd->protocol; + SQL_SELECT *select= 0, *select_cat= 0; + Item *cond_topic, *cond_cat; + st_find_field used_fields[array_elements(init_used_fields)]; DBUG_ENTER("mysqld_help"); + + TABLE_LIST tables[3]; + bzero((gptr)tables,sizeof(tables)); + tables[0].alias= tables[0].real_name= (char*) "help_topic"; + tables[0].lock_type= TL_READ; + tables[0].db= (char*) "mysql"; + tables[0].next= &tables[1]; + tables[1].alias= tables[1].real_name= (char*) "help_category"; + tables[1].lock_type= TL_READ; + tables[1].db= (char*) "mysql"; + tables[1].next= &tables[2]; + tables[2].alias= tables[2].real_name= (char*) "help_relation"; + tables[2].lock_type= TL_READ; + tables[2].db= (char*) "mysql"; + tables[2].next= 0; + + List<char> function_list, categories_list; + char *name, *description, *example; + int res, count_topics, count_categories, error; + + if (open_and_lock_tables(thd, tables)) + { + res= -1; + goto end; + } + /* Init tables and fields to be usable from items */ + setup_tables(tables); + memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); + if (init_fields(thd, tables, used_fields, array_elements(used_fields))) + { + res= -1; + goto end; + } + + /* TODO: Find out why these are needed (should not be) */ + tables[0].table->file->init_table_handle_for_HANDLER(); + tables[1].table->file->init_table_handle_for_HANDLER(); + tables[2].table->file->init_table_handle_for_HANDLER(); + + cond_topic= new Item_func_like(new Item_field(used_fields[help_topic_name]. + field), + new Item_string(mask, strlen(mask), + help_charset), + (char*) "\\"); + cond_topic->fix_fields(thd, tables, &cond_topic); // can never fail + select= make_select(tables[0].table,0,0,cond_topic,&error); + if (error || (select && select->check_quick(0, HA_POS_ERROR))) + { + res= -1; + goto end; + } - MI_INFO *file_leafs= 0; - if (!(file_leafs= open_help_file(thd,"function"))) - DBUG_RETURN(1); - - List<String> function_list, categories_list; - String *name, *description, *example; - int res; - - int count= search_functions(file_leafs, mask, - &function_list,&name,&description,&example); - if (count < 0) + cond_cat= new Item_func_like(new Item_field(used_fields[help_category_name]. + field), + new Item_string(mask, strlen(mask), + help_charset), + (char*) "\\"); + cond_cat->fix_fields(thd, tables, &cond_topic); // can never fail + select_cat= make_select(tables[1].table,0,0,cond_cat,&error); + if (error || (select_cat && select_cat->check_quick(0, HA_POS_ERROR))) { - res= 1; + res= -1; goto end; } - else if (count==0) + + res= 1; + count_topics= search_topics(thd,tables[0].table, used_fields, select, + &function_list, &name, &description, &example); + if (count_topics == 0) { int16 category_id; - count= search_categories(thd, mask, &categories_list, &category_id); - if (count<0) + Item *cond= + new Item_func_like(new + Item_field(used_fields[help_category_name].field), + new Item_string(mask, strlen(mask), + help_charset), + (char*) "\\"); + (void) cond->fix_fields(thd, tables, &cond); // can never fail + + count_categories= search_categories(thd, tables[1].table, used_fields, + select_cat, &categories_list, + &category_id); + if (count_categories == 1) { - res= 1; - goto end; - } - else if (count==1) - { - if ((res= get_all_names_for_category(thd, file_leafs, - category_id,&function_list))) + if (get_all_topics_for_category(thd,tables[0].table, + tables[2].table, used_fields, + category_id, &function_list)) + { + res= -1; goto end; - List_iterator<String> it(function_list); - String *cur_leaf, example; - while ((cur_leaf = it++)) + } + List_iterator<char> it(function_list); + char *cur_topic; + char buff[1024]; + String example(buff, sizeof(buff), help_charset); + example.length(0); + + while ((cur_topic= it++)) { - example.append(*cur_leaf); + example.append(cur_topic); example.append("\n",1); } - if ((res= send_answer_1(protocol, categories_list.head()->ptr(), - "Y","",example.ptr()))) + if ((send_answer_1(protocol, categories_list.head(), + "Y","",example.ptr()))) goto end; } else { - if ((res= send_header_2(protocol)) || - (count==0 && - (search_categories(thd, 0, &categories_list, 0)<0 && - ((res= 1)))) || - (res= send_variant_2_list(protocol,&categories_list,true))) + if (send_header_2(protocol)) + goto end; + if (count_categories == 0) + search_categories(thd,tables[1].table, used_fields, (SQL_SELECT *) 0, + &categories_list, 0); + if (send_variant_2_list(protocol,&categories_list,"Y")) goto end; } } - else if (count==1) + else if (count_topics == 1) { - if ((res= send_answer_1(protocol,name->ptr(),"N", - description->ptr(), example->ptr()))) + if (send_answer_1(protocol,name,"N",description, example)) goto end; } - else if ((res= send_header_2(protocol)) || - (res= send_variant_2_list(protocol,&function_list,false)) || - (search_categories(thd, mask, &categories_list, 0)<0 && - ((res=1))) || - (res= send_variant_2_list(protocol,&categories_list,true))) + else { - goto end; + /* First send header and functions */ + if (send_header_2(protocol) || + send_variant_2_list(protocol, &function_list, "N")) + goto end; + search_categories(thd, tables[1].table, used_fields, select_cat, + &categories_list, 0); + /* Then send categories */ + if (send_variant_2_list(protocol, &categories_list, "Y")) + goto end; } - + res= 0; + send_eof(thd); - end: - mi_close(file_leafs); + delete select; + delete select_cat; DBUG_RETURN(res); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 29d56905788..0fe3d11e404 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -147,6 +147,12 @@ void lex_free(void) } +/* + This is called before every query that is to be parsed. + Because of this, it's critical to not do too much things here. + (We already do too much here) +*/ + LEX *lex_start(THD *thd, uchar *buf,uint length) { LEX *lex= &thd->lex; @@ -164,10 +170,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->thd_charset= lex->thd->variables.thd_charset; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); - lex->slave_thd_opt=0; lex->sql_command=SQLCOM_END; - lex->safe_to_cache_query= 1; - bzero(&lex->mi,sizeof(lex->mi)); return lex; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4ef8ffa840e..00852f302d8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -472,7 +472,7 @@ typedef struct st_lex uint param_count; bool drop_primary, drop_if_exists, drop_temporary, local_file; bool in_comment, ignore_space, verbose, simple_alter; - bool derived_tables, describe, olap; + bool derived_tables, describe; bool safe_to_cache_query; uint slave_thd_opt; CHARSET_INFO *charset; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 08e37a5576b..12666e26295 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -188,7 +188,7 @@ end: static int check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count, bool simple_connect, bool do_send_error, - char* crypted_scramble, bool had_password, + char *crypted_scramble, bool had_password, uint *cur_priv_version, ACL_USER** hint_user) { thd->db=0; @@ -506,10 +506,10 @@ check_connections(THD *thd) char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */ ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */ uint cur_priv_version; - DBUG_PRINT("info", (("check_connections called by thread %d"), - thd->thread_id)); DBUG_PRINT("info",("New connection received on %s", vio_description(net->vio))); + /* Remove warning from valgrind. TODO: Fix it in password.c */ + bzero((char*) prepared_scramble, sizeof(prepared_scramble)); if (!thd->host) // If TCP/IP connection { char ip[30]; @@ -525,15 +525,17 @@ check_connections(THD *thd) thd->host=(char*) localhost; else #endif - if (!(specialflag & SPECIAL_NO_RESOLVE)) { - vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); - /* Cut very long hostnames to avoid possible overflows */ - if (thd->host) - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; - if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); + if (!(specialflag & SPECIAL_NO_RESOLVE)) + { + vio_in_addr(net->vio,&thd->remote.sin_addr); + thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + /* Cut very long hostnames to avoid possible overflows */ + if (thd->host) + thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; + if (connect_errors > max_connect_errors) + return(ER_HOST_IS_BLOCKED); + } } DBUG_PRINT("info",("Host: %s ip: %s", thd->host ? thd->host : "unknown host", @@ -555,8 +557,8 @@ check_connections(THD *thd) { /* buff[] needs to big enough to hold the server_version variable */ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64]; - int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION; + int client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); if (opt_using_transactions) client_flags|=CLIENT_TRANSACTIONS; @@ -582,7 +584,7 @@ check_connections(THD *thd) // At this point we write connection message and read reply if (net_write_command(net,(uchar) protocol_version, "", 0, buff, (uint) (end-buff)) || - (pkt_len= my_net_read(net)) == packet_error || + (pkt_len= my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) { inc_host_errors(&thd->remote.sin_addr); @@ -647,17 +649,17 @@ check_connections(THD *thd) passwd= strend(user)+1; db=0; if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB) - db=strend(passwd)+1; + db=strend(passwd)+1; /* We can get only old hash at this point */ if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH) - return ER_HANDSHAKE_ERROR; + return ER_HANDSHAKE_ERROR; if (thd->client_capabilities & CLIENT_INTERACTIVE) - thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; + thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout; if ((thd->client_capabilities & CLIENT_TRANSACTIONS) && - opt_using_transactions) - net->return_status= &thd->server_status; + opt_using_transactions) + net->return_status= &thd->server_status; net->read_timeout=(uint) thd->variables.net_read_timeout; /* Simple connect only for old clients. New clients always use secure auth */ @@ -665,34 +667,34 @@ check_connections(THD *thd) /* Store information if we used password. passwd will be dammaged */ bool using_password=test(passwd[0]); + /* Check user permissions. If password failure we'll get scramble back */ if (check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect, - simple_connect, prepared_scramble, using_password, &cur_priv_version, - &cached_user)<0) + simple_connect, prepared_scramble, using_password, + &cur_priv_version, + &cached_user)<0) { /* Store current used and database as they are erased with next packet */ char tmp_user[USERNAME_LENGTH+1]; char tmp_db[NAME_LEN+1]; + tmp_user[0]= tmp_db[0]= 0; /* If The client is old we just have to return error */ if (simple_connect) return -1; - tmp_user[0]=0; if (user) strmake(tmp_user,user,USERNAME_LENGTH); - - tmp_db[0]=0; if (db) strmake(tmp_db,db,NAME_LEN); /* Write hash and encrypted scramble to client */ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || net_flush(net)) - { - inc_host_errors(&thd->remote.sin_addr); - return ER_HANDSHAKE_ERROR; - } + { + inc_host_errors(&thd->remote.sin_addr); + return ER_HANDSHAKE_ERROR; + } /* Reading packet back */ if ((pkt_len= my_net_read(net)) == packet_error) { @@ -707,8 +709,9 @@ check_connections(THD *thd) } /* Final attempt to check the user based on reply */ if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos, - tmp_db, 1, 0, 1, prepared_scramble, using_password, &cur_priv_version, - &cached_user)) + tmp_db, 1, 0, 1, prepared_scramble, using_password, + &cur_priv_version, + &cached_user)) return -1; } thd->password=using_password; @@ -774,7 +777,7 @@ pthread_handler_decl(handle_one_connection,arg) net_printf(thd,error,thd->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) - sleep(1); /* must wait after eof() */ + my_sleep(1000); /* must wait after eof() */ #endif statistic_increment(aborted_connects,&LOCK_status); goto end_thread; @@ -1123,22 +1126,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, */ if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect, simple_connect, prepared_scramble, using_password, &cur_priv_version, - &cached_user)<0) + &cached_user) < 0) { /* If The client is old we just have to have auth failure */ if (simple_connect) goto restore_user; /* Error is already reported */ /* Store current used and database as they are erased with next packet */ - tmp_user[0]=0; + tmp_user[0]= tmp_db[0]= 0; if (user) strmake(tmp_user,user,USERNAME_LENGTH); - - tmp_db[0]=0; if (db) strmake(tmp_db,db,NAME_LEN); - /* Write hash and encrypted scramble to client */ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) || net_flush(net)) @@ -1589,7 +1589,6 @@ mysql_execute_command(THD *thd) cursor= cursor->next) { if (cursor->derived && (res=mysql_derived(thd, lex, - (SELECT_LEX_UNIT *) cursor->derived, cursor))) { @@ -1602,7 +1601,7 @@ mysql_execute_command(THD *thd) } if ((&lex->select_lex != lex->all_selects_list && lex->unit.create_total_list(thd, lex, &tables, 0)) -#ifndef EMBEDDED_LIBRARY +#ifndef HAVE_REPLICATION || (table_rules_on && tables && thd->slave_thread && !tables_ok(thd,tables)) @@ -3148,7 +3147,7 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize) /**************************************************************************** - Initialize global thd variables needed for query + Initialize global thd variables needed for query ****************************************************************************/ void @@ -3170,10 +3169,11 @@ mysql_init_query(THD *thd) lex->select_lex.prev= &lex->unit.slave; lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0; lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list); - lex->olap=lex->describe= 0; - lex->derived_tables= false; + lex->describe= 0; + lex->derived_tables= FALSE; lex->lock_option= TL_READ; lex->found_colon= 0; + lex->safe_to_cache_query= 1; thd->select_number= lex->select_lex.select_number= 1; thd->free_list= 0; thd->total_warn_count=0; // Warnings for this query @@ -3184,7 +3184,7 @@ mysql_init_query(THD *thd) thd->tmp_table_used= 0; if (opt_bin_log) reset_dynamic(&thd->user_var_events); - + thd->clear_error(); DBUG_VOID_RETURN; } @@ -3283,8 +3283,6 @@ mysql_parse(THD *thd, char *inBuf, uint length) DBUG_ENTER("mysql_parse"); mysql_init_query(thd); - thd->clear_error(); - if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); @@ -3787,10 +3785,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, my_casedn_str(files_charset_info,table->table.str); ptr->real_name=table->table.str; ptr->real_name_length=table->table.length; - ptr->lock_type= lock_type; + ptr->lock_type= lock_type; ptr->updating= test(table_options & TL_OPTION_UPDATING); ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); - ptr->derived= (SELECT_LEX_UNIT *) table->sel; + ptr->derived= table->sel; if (use_index) ptr->use_index=(List<String> *) thd->memdup((gptr) use_index, sizeof(*use_index)); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 086d22b17d4..3cb4c4e8244 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -669,11 +669,10 @@ static bool parse_prepare_query(PREP_STMT *stmt, mysql_log.write(thd,COM_PREPARE,"%s",packet); mysql_init_query(thd); - thd->prepare_command=true; - thd->lex.param_count= 0; - LEX *lex=lex_start(thd, (uchar*) packet, length); lex->safe_to_cache_query= 0; + thd->prepare_command= TRUE; + thd->lex.param_count= 0; if (!yyparse((void *)thd) && !thd->is_fatal_error) error= send_prepare_results(stmt); lex_end(lex); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 66168459c7a..81adda55deb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -670,6 +670,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, ER(ER_WRONG_ARGUMENTS),MYF(0),"RTREE INDEX"); DBUG_RETURN(-1); } + /* TODO: To be deleted */ + my_printf_error(ER_NOT_SUPPORTED_YET, ER(ER_NOT_SUPPORTED_YET), + MYF(0), "RTREE INDEX"); + DBUG_RETURN(-1); } List_iterator<key_part_spec> cols(key->columns); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 39800ae6206..387c9970e34 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -162,9 +162,9 @@ void udf_init() { DBUG_PRINT("info",("init udf record")); LEX_STRING name; - name.str=get_field(&mem, table, 0); + name.str=get_field(&mem, table->field[0]); name.length = strlen(name.str); - char *dl_name= get_field(&mem, table, 2); + char *dl_name= get_field(&mem, table->field[2]); bool new_dl=0; Item_udftype udftype=UDFTYPE_FUNCTION; if (table->fields >= 4) // New func table diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 44f63a2abe3..bc1e61377a9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -136,6 +136,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token EVENTS_SYM %token EXECUTE_SYM %token FLUSH_SYM +%token HELP_SYM %token INSERT %token IO_THREAD %token KILL_SYM @@ -528,8 +529,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SUBJECT_SYM %token CIPHER_SYM -%token HELP - %left SET_VAR %left OR_OR_CONCAT OR %left AND @@ -742,11 +741,11 @@ verb_clause: /* help */ help: - HELP TEXT_STRING + HELP_SYM ident_or_text { - LEX *lex= Lex; - lex->sql_command= SQLCOM_HELP; - lex->help_arg= $2.str; + LEX *lex= Lex; + lex->sql_command= SQLCOM_HELP; + lex->help_arg= $2.str; }; /* change master */ @@ -1573,8 +1572,13 @@ start: ; slave_thread_opts: + { Lex->slave_thd_opt= 0; } + slave_thread_opt_list + +slave_thread_opt_list: slave_thread_opt - | slave_thread_opts ',' slave_thread_opt; + | slave_thread_opt_list ',' slave_thread_opt + ; slave_thread_opt: /*empty*/ {} @@ -1720,7 +1724,8 @@ select_init: send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } - if (sel->linkage == UNION_TYPE && !sel->master_unit()->first_select()->braces) + if (sel->linkage == UNION_TYPE && + !sel->master_unit()->first_select()->braces) { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; @@ -1740,7 +1745,8 @@ select_init2: send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } - if (sel->linkage == UNION_TYPE && sel->master_unit()->first_select()->braces) + if (sel->linkage == UNION_TYPE && + sel->master_unit()->first_select()->braces) { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; @@ -2773,7 +2779,6 @@ olap_opt: | WITH CUBE_SYM { LEX *lex=Lex; - lex->olap= 1; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { net_printf(lex->thd, ER_WRONG_USAGE, "WITH CUBE", @@ -2787,7 +2792,6 @@ olap_opt: | WITH ROLLUP_SYM { LEX *lex= Lex; - lex->olap= 1; if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { net_printf(lex->thd, ER_WRONG_USAGE, "WITH ROLLUP", @@ -2812,7 +2816,7 @@ order_clause: ORDER_SYM BY { LEX *lex=Lex; - if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && + if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE) && lex->current_select->select_lex()->olap != UNSPECIFIED_OLAP_TYPE) { @@ -2835,11 +2839,21 @@ order_dir: | DESC { $$ =0; }; -opt_limit_clause: - /* empty */ {} +opt_limit_clause_init: + /* empty */ + { + SELECT_LEX_NODE *sel= Select; + sel->offset_limit= 0L; + sel->select_limit= Lex->thd->variables.select_limit; + } | limit_clause {} ; +opt_limit_clause: + /* empty */ {} + | limit_clause {} + ; + limit_clause: LIMIT { @@ -3423,9 +3437,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; - lex->select_lex.select_limit= lex->thd->variables.select_limit; - lex->select_lex.offset_limit= 0L; - } opt_limit_clause + } opt_limit_clause_init | keys_or_index FROM table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS; @@ -3453,9 +3465,9 @@ show_param: { (void) create_select_for_variable("warning_count"); } | COUNT_SYM '(' '*' ')' ERRORS { (void) create_select_for_variable("error_count"); } - | WARNINGS {Select->offset_limit=0L;} opt_limit_clause + | WARNINGS opt_limit_clause_init { Lex->sql_command = SQLCOM_SHOW_WARNS;} - | ERRORS {Select->offset_limit=0L;} opt_limit_clause + | ERRORS opt_limit_clause_init { Lex->sql_command = SQLCOM_SHOW_ERRORS;} | STATUS_SYM wild { Lex->sql_command= SQLCOM_SHOW_STATUS; } @@ -3729,18 +3741,24 @@ opt_ignore_lines: /* Common definitions */ text_literal: - TEXT_STRING { $$ = new Item_string($1.str,$1.length,YYTHD->variables.thd_charset); } - | UNDERSCORE_CHARSET TEXT_STRING { $$ = new Item_string($2.str,$2.length,Lex->charset); } + TEXT_STRING + { $$ = new Item_string($1.str,$1.length, + YYTHD->variables.thd_charset); } + | UNDERSCORE_CHARSET TEXT_STRING + { $$ = new Item_string($2.str,$2.length,Lex->charset); } | text_literal TEXT_STRING - { ((Item_string*) $1)->append($2.str,$2.length); }; + { ((Item_string*) $1)->append($2.str,$2.length); }; text_string: - TEXT_STRING { $$= new String($1.str,$1.length,YYTHD->variables.thd_charset); } + TEXT_STRING + { $$= new String($1.str,$1.length,YYTHD->variables.thd_charset); } | HEX_NUM { Item *tmp = new Item_varbinary($1.str,$1.length); $$= tmp ? tmp->val_str((String*) 0) : (String*) 0; - }; + } + ; + param_marker: '?' { @@ -3755,7 +3773,9 @@ param_marker: yyerror("You have an error in your SQL syntax"); YYABORT; } - }; + } + ; + literal: text_literal { $$ = $1; } | NUM { $$ = new Item_int($1.str, (longlong) strtol($1.str, NULL, 10),$1.length); } @@ -3948,8 +3968,9 @@ keyword: | FLUSH_SYM {} | GRANTS {} | GLOBAL_SYM {} - | HEAP_SYM {} | HANDLER_SYM {} + | HEAP_SYM {} + | HELP_SYM {} | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} @@ -4255,7 +4276,7 @@ handler: if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0)) YYABORT; } - handler_read_or_scan where_clause opt_limit_clause { } + handler_read_or_scan where_clause opt_limit_clause {} ; handler_read_or_scan: @@ -4633,8 +4654,6 @@ optional_order_or_limit: sel->master_unit()->global_parameters= sel->master_unit(); lex->current_select= sel->master_unit(); - lex->current_select->select_limit= - lex->thd->variables.select_limit; lex->current_select->no_table_names_allowed= 1; thd->where= "global ORDER clause"; } @@ -4647,9 +4666,8 @@ optional_order_or_limit: ; order_or_limit: - order_clause opt_limit_clause - | - limit_clause + order_clause opt_limit_clause_init + | limit_clause ; union_option: diff --git a/sql/table.cc b/sql/table.cc index a54cc4d5a73..dd5a957f984 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -37,7 +37,27 @@ static byte* get_field_name(Field *buff,uint *length, return (byte*) buff->field_name; } - /* Open a .frm file */ +/* + Open a .frm file + + SYNOPSIS + openfrm() + + name path to table-file "db/name" + alias alias for table + db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..) + can be 0 (example in ha_example_table) + prgflag READ_ALL etc.. + ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc.. + outparam result table + + RETURN VALUES + 0 ok + 1 Error (see frm_error) + 2 Error (see frm_error) + 3 Wrong data in .frm file + 4 Error (see frm_error) +*/ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, uint ha_open_flags, TABLE *outparam) @@ -1127,13 +1147,20 @@ rename_file_ext(const char * from,const char * to,const char * ext) /* - Alloc a value as a string and return it - If field is empty, return NULL + Allocate string field in MEM_ROOT and return it as NULL-terminated string + + SYNOPSIS + get_field() + mem MEM_ROOT for allocating + field Field for retrieving of string + + RETURN VALUES + NullS string is empty + # pointer to NULL-terminated string value of field */ -char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr) +char *get_field(MEM_ROOT *mem, Field *field) { - Field *field=table->field[fieldnr]; char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff),default_charset_info); field->val_str(&str,&str); diff --git a/sql/table.h b/sql/table.h index ceffdcc9dc7..1f7df0c6d64 100644 --- a/sql/table.h +++ b/sql/table.h @@ -19,6 +19,7 @@ class Item; /* Needed by ORDER */ class GRANT_TABLE; +class st_select_lex_unit; /* Order clause list element */ @@ -161,7 +162,7 @@ typedef struct st_table_list TABLE *table; /* opened table */ st_table_list *table_list; /* pointer to node of list of all tables */ }; - void *derived; /* SELECT_LEX_UNIT of derived table */ + class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ GRANT_INFO grant; thr_lock_type lock_type; uint outer_join; /* Which join type */ diff --git a/sql/time.cc b/sql/time.cc index 96f628dbb14..6b2f8b710da 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -436,7 +436,8 @@ ulong convert_month_to_period(ulong month) Also dates where all parts are zero are allowed RETURN VALUES - TIMESTAMP_NONE String wasn't a timestamp + TIMESTAMP_NONE String wasn't a timestamp, like + [DD [HH:[MM:[SS]]]].fraction TIMESTAMP_DATE DATE string (YY MM and DD parts ok) TIMESTAMP_FULL Full timestamp */ @@ -448,6 +449,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) uint not_zero_date; const char *pos; const char *end=str+length; + bool found_delimitier= 0; DBUG_ENTER("str_to_TIME"); DBUG_PRINT("enter",("str: %.*s",length,str)); @@ -456,7 +458,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) if (str == end) DBUG_RETURN(TIMESTAMP_NONE); /* - calculate first number of digits. + Calculate first number of digits. If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ @@ -474,6 +476,11 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); str++; } + if (found_delimitier && (int) field_length < 0) + { + /* The number can't match any valid date or datetime string */ + DBUG_RETURN(TIMESTAMP_NONE); + } date[i]=tmp_value; not_zero_date|= tmp_value; if (i == 2 && str != end && *str == 'T') @@ -488,6 +495,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) if (my_isspace(&my_charset_latin1,*str) && i != 2) DBUG_RETURN(TIMESTAMP_NONE); str++; + found_delimitier=1; // Should be a 'normal' date } } field_length=1; // Rest fields can only be 2 @@ -498,7 +506,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) { str++; uint tmp_value=(uint) (uchar) (*str - '0'); - field_length=3; + field_length=5; while (str++ != end && my_isdigit(&my_charset_latin1,str[0]) && field_length--) tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); @@ -583,12 +591,22 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date) } -/***************************************************************************** -** convert a time string to a (ulong) value. -** Can use all full timestamp formats and -** [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS, [M]MSS or [S]S -** There may be an optional [.second_part] after seconds -*****************************************************************************/ +/* + Convert a time string to a TIME struct. + + SYNOPSIS + str_to_time() + str A string in full TIMESTAMP format or + [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS, + [M]MSS or [S]S + There may be an optional [.second_part] after seconds + length Length of str + l_time Store result here + + RETURN + 0 ok + 1 error +*/ bool str_to_time(const char *str,uint length,TIME *l_time) { diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 4d428828826..c219bd95fd4 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -22,24 +22,48 @@ #include "m_string.h" #include "m_ctype.h" -static uchar ctype_bin[] = { - 0, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +static uchar ctype_bin[]= +{ + 0, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 132,132,132,132,132,132,132,132,132,132, 16, 16, 16, 16, 16, 16, - 16,129,129,129,129,129,129, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, - 16,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2 + 16,129,129,129,129,129,129, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 16, 16, 16, 16, + 16,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2 +}; + + +/* Dummy array for toupper / tolower / sortorder */ + +static uchar bin_char_array[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 }; @@ -277,9 +301,9 @@ CHARSET_INFO my_charset_bin = "binary", /* name */ "", /* comment */ ctype_bin, /* ctype */ - NULL, /* to_lower */ - NULL, /* to_upper */ - NULL, /* sort_order */ + bin_char_array, /* to_lower */ + bin_char_array, /* to_upper */ + bin_char_array, /* sort_order */ NULL, /* tab_to_uni */ NULL, /* tab_from_uni */ 0, /* strxfrm_multiply */ |