summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@mashka.mysql.fi>2003-02-12 21:55:37 +0200
committerunknown <monty@mashka.mysql.fi>2003-02-12 21:55:37 +0200
commitfcb61f5917ee69bba91bd6a926db2eab4ac3eeb5 (patch)
tree3ac37e452f15c8f05e9d1f338a6050281f838048
parent363fd89b92de2fc58e7910f7a27684308656ebda (diff)
downloadmariadb-git-fcb61f5917ee69bba91bd6a926db2eab4ac3eeb5.tar.gz
Fixed a lot of wrong memory references as reported by valgrind
Portability fixes Added new client function: mysql_get_server_version() New server help code (From Victor Vagin) Fixed wrong usage of binary() Disabled RTREE usage for now. BitKeeper/etc/ignore: added scripts/fill_help_tables.sql client/mysql.cc: Some fixes when using 'help' cmd-line-utils/libedit/compat.h: Portability fix cmd-line-utils/libedit/fgetln.c: Portability fix include/mysql.h: Added new client function: mysql_get_server_version() libmysql/libmysql.c: Added new client function: mysql_get_server_version() libmysqld/libmysqld.c: Fixed prototype mysql-test/install_test_db.sh: Added creation of help tables mysql-test/r/connect.result: Added help tables mysql-test/r/myisam.result: Test of RTREE index mysql-test/r/type_ranges.result: updated results mysql-test/t/myisam.test: Test of RTREE index mysql-test/t/type_ranges.test: Updated test mysys/charset.c: Indentation change mysys/my_symlink.c: Removed compiler warning scripts/fill_help_tables.sh: Update for new help tables sql/field.cc: Indentation changes sql/filesort.cc: Optimized character set usage sql/item_cmpfunc.cc: Fix wrong usage of binary() sql/item_cmpfunc.h: Fix wrong usage of binary() sql/item_func.cc: Fix wrong usage of binary() sql/item_func.h: Fix wrong usage of binary() sql/item_strfunc.cc: Fix wrong usage of binary() sql/item_sum.cc: Fix wrong usage of binary() sql/item_sum.h: Fix wrong usage of binary() sql/key.cc: Indentation change sql/lex.h: HELP -> HELP_SYM sql/mysql_priv.h: Make get_field() more general sql/password.c: Indentation change + variable initialisation moved sql/sql_acl.cc: Make get_field() more general sql/sql_base.cc: Added comments + assertion for double call to mysql_lock_tables sql/sql_cache.cc: Indentation changes sql/sql_class.h: Added need_strxnfrm to SORT_FIELD to be able to optimise character set handling in filesort sql/sql_derived.cc: Renamed variables sql/sql_help.cc: New help functions (from Victor Vagin) sql/sql_lex.cc: Removed variables that doesn't have to be initialized for each query sql/sql_lex.h: Removed not used variable (olap) sql/sql_parse.cc: Fixed (not fatal) access of unitialized memory Indentation / code cleanup sql/sql_prepare.cc: Indentaion cleanup sql/sql_table.cc: Disabled RTREE until 5.0 sql/sql_udf.cc: Make get_field() more general sql/sql_yacc.yy: Removed access to uninitialized memory Always set offset_limit and select_limit when using LIMIT (removed warnings) Allow usage of 'help week' sql/table.cc: Make get_field() more general More comments sql/table.h: Fixded type of TABLE_LIST->derived sql/time.cc: Stricter date / datetime handling (to be able to handle timestamps with days and microseconds) strings/ctype-bin.c: Added cha
-rw-r--r--.bzrignore1
-rw-r--r--client/mysql.cc35
-rw-r--r--cmd-line-utils/libedit/compat.h4
-rw-r--r--cmd-line-utils/libedit/fgetln.c3
-rw-r--r--include/mysql.h1
-rw-r--r--libmysql/libmysql.c29
-rw-r--r--libmysqld/libmysqld.c2
-rw-r--r--mysql-test/install_test_db.sh43
-rw-r--r--mysql-test/r/connect.result9
-rw-r--r--mysql-test/r/help.result123
-rw-r--r--mysql-test/r/myisam.result5
-rw-r--r--mysql-test/r/type_ranges.result2
-rw-r--r--mysql-test/t/help.test50
-rw-r--r--mysql-test/t/myisam.test9
-rw-r--r--mysql-test/t/type_ranges.test2
-rw-r--r--mysys/charset.c2
-rw-r--r--mysys/my_symlink.c3
-rw-r--r--scripts/fill_help_tables.sh67
-rw-r--r--sql/field.cc8
-rw-r--r--sql/filesort.cc80
-rw-r--r--sql/item_cmpfunc.cc46
-rw-r--r--sql/item_cmpfunc.h46
-rw-r--r--sql/item_func.cc28
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_strfunc.cc8
-rw-r--r--sql/item_sum.cc12
-rw-r--r--sql/item_sum.h4
-rw-r--r--sql/key.cc3
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/password.c47
-rw-r--r--sql/sql_acl.cc61
-rw-r--r--sql/sql_base.cc68
-rw-r--r--sql/sql_cache.cc3
-rw-r--r--sql/sql_class.h6
-rw-r--r--sql/sql_derived.cc21
-rw-r--r--sql/sql_help.cc647
-rw-r--r--sql/sql_lex.cc9
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc90
-rw-r--r--sql/sql_prepare.cc5
-rw-r--r--sql/sql_table.cc4
-rw-r--r--sql/sql_udf.cc4
-rw-r--r--sql/sql_yacc.yy82
-rw-r--r--sql/table.cc37
-rw-r--r--sql/table.h3
-rw-r--r--sql/time.cc36
-rw-r--r--strings/ctype-bin.c64
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*) &param,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,
+ &not_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 */