Commit a350e53b authored by Sergei Golubchik's avatar Sergei Golubchik

Merge branch 'mysql/5.5' into 5.5

without a fix for Bug#12818255 (MDEV-6581)
parents 511313b9 7d57772f
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
/* Global Thread counter */ /* Global Thread counter */
uint counter= 0; uint counter= 0;
pthread_mutex_t init_mutex;
pthread_mutex_t counter_mutex; pthread_mutex_t counter_mutex;
pthread_cond_t count_threshhold; pthread_cond_t count_threshhold;
...@@ -421,6 +422,17 @@ static MYSQL *db_connect(char *host, char *database, ...@@ -421,6 +422,17 @@ static MYSQL *db_connect(char *host, char *database,
MYSQL *mysql; MYSQL *mysql;
if (verbose) if (verbose)
fprintf(stdout, "Connecting to %s\n", host ? host : "localhost"); fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
if (opt_use_threads && !lock_tables)
{
pthread_mutex_lock(&init_mutex);
if (!(mysql= mysql_init(NULL)))
{
pthread_mutex_unlock(&init_mutex);
return 0;
}
pthread_mutex_unlock(&init_mutex);
}
else
if (!(mysql= mysql_init(NULL))) if (!(mysql= mysql_init(NULL)))
return 0; return 0;
if (opt_compress) if (opt_compress)
...@@ -605,7 +617,7 @@ pthread_handler_t worker_thread(void *arg) ...@@ -605,7 +617,7 @@ pthread_handler_t worker_thread(void *arg)
pthread_cond_signal(&count_threshhold); pthread_cond_signal(&count_threshhold);
pthread_mutex_unlock(&counter_mutex); pthread_mutex_unlock(&counter_mutex);
mysql_thread_end(); mysql_thread_end();
pthread_exit(0);
return 0; return 0;
} }
...@@ -629,15 +641,31 @@ int main(int argc, char **argv) ...@@ -629,15 +641,31 @@ int main(int argc, char **argv)
if (opt_use_threads && !lock_tables) if (opt_use_threads && !lock_tables)
{ {
pthread_t mainthread; /* Thread descriptor */ char **save_argv;
uint worker_thread_count= 0, table_count= 0, i= 0;
pthread_t *worker_threads; /* Thread descriptor */
pthread_attr_t attr; /* Thread attributes */ pthread_attr_t attr; /* Thread attributes */
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_DETACHED); PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&init_mutex, NULL);
pthread_mutex_init(&counter_mutex, NULL); pthread_mutex_init(&counter_mutex, NULL);
pthread_cond_init(&count_threshhold, NULL); pthread_cond_init(&count_threshhold, NULL);
/* Count the number of tables. This number denotes the total number
of threads spawn.
*/
save_argv= argv;
for (table_count= 0; *argv != NULL; argv++)
table_count++;
argv= save_argv;
if (!(worker_threads= (pthread_t*) my_malloc(table_count *
sizeof(*worker_threads),
MYF(0))))
return -2;
for (counter= 0; *argv != NULL; argv++) /* Loop through tables */ for (counter= 0; *argv != NULL; argv++) /* Loop through tables */
{ {
pthread_mutex_lock(&counter_mutex); pthread_mutex_lock(&counter_mutex);
...@@ -652,15 +680,16 @@ int main(int argc, char **argv) ...@@ -652,15 +680,16 @@ int main(int argc, char **argv)
counter++; counter++;
pthread_mutex_unlock(&counter_mutex); pthread_mutex_unlock(&counter_mutex);
/* now create the thread */ /* now create the thread */
if (pthread_create(&mainthread, &attr, worker_thread, if (pthread_create(&worker_threads[worker_thread_count], &attr,
(void *)*argv) != 0) worker_thread, (void *)*argv) != 0)
{ {
pthread_mutex_lock(&counter_mutex); pthread_mutex_lock(&counter_mutex);
counter--; counter--;
pthread_mutex_unlock(&counter_mutex); pthread_mutex_unlock(&counter_mutex);
fprintf(stderr,"%s: Could not create thread\n", fprintf(stderr,"%s: Could not create thread\n", my_progname);
my_progname); continue;
} }
worker_thread_count++;
} }
/* /*
...@@ -675,9 +704,18 @@ int main(int argc, char **argv) ...@@ -675,9 +704,18 @@ int main(int argc, char **argv)
pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
} }
pthread_mutex_unlock(&counter_mutex); pthread_mutex_unlock(&counter_mutex);
pthread_mutex_destroy(&init_mutex);
pthread_mutex_destroy(&counter_mutex); pthread_mutex_destroy(&counter_mutex);
pthread_cond_destroy(&count_threshhold); pthread_cond_destroy(&count_threshhold);
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
for(i= 0; i < worker_thread_count; i++)
{
if (pthread_join(worker_threads[i], NULL))
fprintf(stderr,"%s: Could not join worker thread.\n", my_progname);
}
my_free(worker_threads);
} }
else else
{ {
......
...@@ -574,3 +574,10 @@ drop table t1; ...@@ -574,3 +574,10 @@ drop table t1;
# #
# End of 5.5 tests # End of 5.5 tests
# #
SELECT NAME_CONST('a', -(1 OR 2)) OR 1;
ERROR HY000: Incorrect arguments to NAME_CONST
SELECT NAME_CONST('a', -(1 AND 2)) OR 1;
ERROR HY000: Incorrect arguments to NAME_CONST
SELECT NAME_CONST('a', -(1)) OR 1;
NAME_CONST('a', -(1)) OR 1
1
...@@ -507,7 +507,7 @@ DROP TABLE t1; ...@@ -507,7 +507,7 @@ DROP TABLE t1;
# Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U # Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
# #
CREATE TABLE t1(f1 INT); CREATE TABLE t1(f1 INT);
SELECT 0xE1BB30 INTO OUTFILE 't1.dat'; SELECT 0xE1C330 INTO OUTFILE 't1.dat';
LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8; LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
DROP TABLE t1; DROP TABLE t1;
# #
...@@ -532,3 +532,27 @@ FIELDS TERMINATED BY 't' LINES TERMINATED BY ''; ...@@ -532,3 +532,27 @@ FIELDS TERMINATED BY 't' LINES TERMINATED BY '';
Got one of the listed errors Got one of the listed errors
SET @@sql_mode= @old_mode; SET @@sql_mode= @old_mode;
DROP TABLE t1; DROP TABLE t1;
#
# Bug#23080148 - Backport of Bug#20683959.
# Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY
# UNDER DB CHARSET IS UTF8.
#
CREATE DATABASE d1 CHARSET latin1;
USE d1;
CREATE TABLE t1 (val TEXT);
LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)
1
SELECT HEX(val) FROM t1;
HEX(val)
C38322525420406E696F757A656368756E3A20E98198E2889AF58081AEE7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE78999E880B3E7B8BAEFBDAAE7B9A7E89699E296A1E7B8BAE4BBA3EFBD8CE7B8BAEFBDA9E7B8B2E2889AE38184E7B99DEFBDB3E7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE5B3A8EFBD84E8ABA0EFBDA8E89C89F580948EE599AAE7B8BAEFBDAAE7B8BAE9A198EFBDA9EFBDB1E7B9A7E581B5E289A0E7B8BAEFBDBEE7B9A7E9A194EFBDA9E882B4EFBDA5EFBDB5E980A7F5808B96E28693E99EABE38287E58F99E7B8BAE58AB1E28691E7B8BAF5808B9AE7828AE98095EFBDB1E7B8BAEFBDAFE7B8B2E288ABE6A89FE89EB3E6BA98F58081ADE88EA0EFBDBAE98095E6BA98F58081AEE89D93EFBDBAE8AD9BEFBDACE980A7F5808B96E28693E7B8BAF580918EE288AAE7B8BAE4B88AEFBC9EE7B8BAE4B99DE28691E7B8BAF5808B96EFBCA0E88DB3E6A68AEFBDB9EFBDB3E981B2E5B3A8E296A1E7B8BAE7A4BCE7828AE88DB3E6A68AEFBDB0EFBDBDE7B8BAA0E7B8BAE88B93EFBDBEE5B899EFBC9E
CREATE DATABASE d2 CHARSET utf8;
USE d2;
CREATE TABLE t1 (val TEXT);
LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
ERROR HY000: Invalid utf8 character string: '"RT @niouzechun: \9058\221A'
DROP TABLE d1.t1, d2.t1;
DROP DATABASE d1;
DROP DATABASE d2;
...@@ -320,3 +320,23 @@ c2 ...@@ -320,3 +320,23 @@ c2
DROP TRIGGER t1_ai; DROP TRIGGER t1_ai;
DROP TABLE t1, t2; DROP TABLE t1, t2;
End of 5.0 tests End of 5.0 tests
#
# Bug#21142859: FUNCTION UPDATING A VIEW FAILS TO FIND TABLE THAT ACTUALLY EXISTS
#
CREATE TABLE t1 SELECT 1 AS fld1, 'A' AS fld2;
CREATE TABLE t2 (fld3 INT, fld4 CHAR(1));
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE TRIGGER t1_au AFTER UPDATE ON t1
FOR EACH ROW INSERT INTO t2 VALUES (new.fld1, new.fld2);
CREATE FUNCTION f1() RETURNS INT
BEGIN
UPDATE v1 SET fld2='B' WHERE fld1=1;
RETURN row_count();
END !
# Without the patch, an error was getting reported.
SELECT f1();
f1()
1
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1,t2;
Ã"RT @niouzechun: 遘√繝上ャ繝斐繧ィ繝ウ繝牙耳縺ェ繧薙□縺代l縺ゥ縲√い繝ウ繝上ャ繝斐繧ィ繝ウ繝峨d諠ィ蜉噪縺ェ縺願ゥア繧偵≠縺セ繧顔ゥ肴・オ逧↓鞫ょ叙縺励↑縺炊逕ア縺ッ縲∫樟螳溘莠コ逕溘蝓コ譛ャ逧↓縺∪縺上>縺九↑縺@荳榊ケウ遲峨□縺礼炊荳榊ース縺縺苓セ帙>
DROP TABLE IF EXISTS t1 ;
# READ_ONLY does nothing to SUPER users
# so we use a non-SUPER one:
GRANT CREATE, SELECT, DROP ON *.* TO test@localhost;
connect con1,localhost,test,,test;
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB;
# Test INSERTS with autocommit being off and on.
BEGIN;
INSERT INTO t1 VALUES (10);
COMMIT;
INSERT INTO t1 VALUES (20);
# Test UPDATES with autocommit being off and on.
BEGIN;
UPDATE t1 SET a=30 WHERE a=10;
COMMIT;
UPDATE t1 SET a=40 WHERE a=20;
connection default;
SET GLOBAL READ_ONLY=0;
# Test scenario where global read_only is enabled in the middle of transaction.
# Test INSERT operations on temporary tables, INSERTs should be successful even
# when global read_only is enabled.
connection con1;
BEGIN;
INSERT INTO t1 VALUES(50);
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
SELECT @@GLOBAL.READ_ONLY;
@@GLOBAL.READ_ONLY
1
COMMIT;
connection default;
SET GLOBAL READ_ONLY=0;
# Test UPDATE operations on temporary tables, UPDATEs should be successful even
# when global read_only is enabled.
connection con1;
BEGIN;
UPDATE t1 SET a=60 WHERE a=50;
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
SELECT @@GLOBAL.READ_ONLY;
@@GLOBAL.READ_ONLY
1
COMMIT;
SELECT * FROM t1;
a
30
40
60
# Clean up
connection default;
SET GLOBAL READ_ONLY=0;
disconnect con1;
DROP USER test@localhost;
# ==== Purpose ====
#
# Check that DMLs are allowed on temporary tables, when server is in read only
# mode and binary log is enabled with binlog-format being stmt/mixed mode.
#
# ==== Implementation ====
#
# Start the server with binary log being enabled. Mark the server as read only.
# Create a non-SUPER user and let the user to create a temporary table and
# perform DML operations on that temporary table. DMLs should not be blocked
# with a 'server read-only mode' error.
#
# ==== References ====
#
# Bug#12818255: READ-ONLY OPTION DOES NOT ALLOW INSERTS/UPDATES ON TEMPORARY
# TABLES
# Bug#14294223: CHANGES NOT ALLOWED TO TEMPORARY TABLES ON READ-ONLY SERVERS
###############################################################################
--source include/have_log_bin.inc
--source include/have_innodb.inc
--disable_warnings
DROP TABLE IF EXISTS t1 ;
--enable_warnings
--enable_connect_log
--echo # READ_ONLY does nothing to SUPER users
--echo # so we use a non-SUPER one:
GRANT CREATE, SELECT, DROP ON *.* TO test@localhost;
connect (con1,localhost,test,,test);
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB;
--echo # Test INSERTS with autocommit being off and on.
BEGIN;
INSERT INTO t1 VALUES (10);
COMMIT;
INSERT INTO t1 VALUES (20);
--echo # Test UPDATES with autocommit being off and on.
BEGIN;
UPDATE t1 SET a=30 WHERE a=10;
COMMIT;
UPDATE t1 SET a=40 WHERE a=20;
connection default;
SET GLOBAL READ_ONLY=0;
--echo # Test scenario where global read_only is enabled in the middle of transaction.
--echo # Test INSERT operations on temporary tables, INSERTs should be successful even
--echo # when global read_only is enabled.
connection con1;
BEGIN;
INSERT INTO t1 VALUES(50);
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
SELECT @@GLOBAL.READ_ONLY;
COMMIT;
connection default;
SET GLOBAL READ_ONLY=0;
--echo # Test UPDATE operations on temporary tables, UPDATEs should be successful even
--echo # when global read_only is enabled.
connection con1;
BEGIN;
UPDATE t1 SET a=60 WHERE a=50;
connection default;
SET GLOBAL READ_ONLY=1;
connection con1;
SELECT @@GLOBAL.READ_ONLY;
COMMIT;
SELECT * FROM t1;
--echo # Clean up
connection default;
SET GLOBAL READ_ONLY=0;
disconnect con1;
DROP USER test@localhost;
--disable_connect_log
...@@ -599,3 +599,13 @@ drop table t1; ...@@ -599,3 +599,13 @@ drop table t1;
--echo # --echo #
--echo # End of 5.5 tests --echo # End of 5.5 tests
--echo # --echo #
#
# Bug#12735545 - PARSER STACK OVERFLOW WITH NAME_CONST
# CONTAINING OR EXPRESSION
#
--error ER_WRONG_ARGUMENTS
SELECT NAME_CONST('a', -(1 OR 2)) OR 1;
--error ER_WRONG_ARGUMENTS
SELECT NAME_CONST('a', -(1 AND 2)) OR 1;
SELECT NAME_CONST('a', -(1)) OR 1;
...@@ -612,7 +612,7 @@ disconnect con1; ...@@ -612,7 +612,7 @@ disconnect con1;
--echo # --echo #
CREATE TABLE t1(f1 INT); CREATE TABLE t1(f1 INT);
EVAL SELECT 0xE1BB30 INTO OUTFILE 't1.dat'; EVAL SELECT 0xE1C330 INTO OUTFILE 't1.dat';
--disable_warnings --disable_warnings
LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8; LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
--enable_warnings --enable_warnings
...@@ -658,3 +658,26 @@ SET @@sql_mode= @old_mode; ...@@ -658,3 +658,26 @@ SET @@sql_mode= @old_mode;
--remove_file $MYSQLTEST_VARDIR/mysql --remove_file $MYSQLTEST_VARDIR/mysql
DROP TABLE t1; DROP TABLE t1;
--echo
--echo #
--echo # Bug#23080148 - Backport of Bug#20683959.
--echo # Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY
--echo # UNDER DB CHARSET IS UTF8.
--echo #
CREATE DATABASE d1 CHARSET latin1;
USE d1;
CREATE TABLE t1 (val TEXT);
LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
SELECT COUNT(*) FROM t1;
SELECT HEX(val) FROM t1;
CREATE DATABASE d2 CHARSET utf8;
USE d2;
CREATE TABLE t1 (val TEXT);
--error ER_INVALID_CHARACTER_STRING
LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
DROP TABLE d1.t1, d2.t1;
DROP DATABASE d1;
DROP DATABASE d2;
...@@ -388,3 +388,29 @@ DROP TABLE t1, t2; ...@@ -388,3 +388,29 @@ DROP TABLE t1, t2;
--echo End of 5.0 tests --echo End of 5.0 tests
--echo #
--echo # Bug#21142859: FUNCTION UPDATING A VIEW FAILS TO FIND TABLE THAT ACTUALLY EXISTS
--echo #
CREATE TABLE t1 SELECT 1 AS fld1, 'A' AS fld2;
CREATE TABLE t2 (fld3 INT, fld4 CHAR(1));
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE TRIGGER t1_au AFTER UPDATE ON t1
FOR EACH ROW INSERT INTO t2 VALUES (new.fld1, new.fld2);
DELIMITER !;
CREATE FUNCTION f1() RETURNS INT
BEGIN
UPDATE v1 SET fld2='B' WHERE fld1=1;
RETURN row_count();
END !
DELIMITER ;!
--echo # Without the patch, an error was getting reported.
SELECT f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1,t2;
...@@ -159,6 +159,10 @@ char *argv[]; ...@@ -159,6 +159,10 @@ char *argv[];
if (argc > 4) if (argc > 4)
for (n = atoi(argv[3]); n > 0; n--) { for (n = atoi(argv[3]); n > 0; n--) {
if(sizeof(buf)-1 < strlen(argv[1]))
{
exit(EXIT_FAILURE);
}
(void) strcpy(buf, argv[1]); (void) strcpy(buf, argv[1]);
} }
else if (argc > 3) else if (argc > 3)
......
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. /* Copyright (c) 2000, 2016, Oracle and/or its affiliates.
Copyright (c) 2010, 2016, MariaDB Copyright (c) 2010, 2016, MariaDB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
...@@ -5371,6 +5371,15 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx, ...@@ -5371,6 +5371,15 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx,
&table_list->view->sroutines_list, &table_list->view->sroutines_list,
table_list->top_table()); table_list->top_table());
} }
/*
If a trigger was defined on one of the associated tables then assign the
'trg_event_map' value of the view to the next table in table_list. When a
Stored function is invoked, all the associated tables including the tables
associated with the trigger are prelocked.
*/
if (table_list->trg_event_map && table_list->next_global)
table_list->next_global->trg_event_map= table_list->trg_event_map;
return FALSE; return FALSE;
} }
......
...@@ -1389,8 +1389,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, ...@@ -1389,8 +1389,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
set_if_bigger(length,line_start.length()); set_if_bigger(length,line_start.length());
stack=stack_pos=(int*) sql_alloc(sizeof(int)*length); stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0)))) if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME))))
error=1; /* purecov: inspected */ error= true; /* purecov: inspected */
else else
{ {
end_of_buff=buffer+buff_length; end_of_buff=buffer+buff_length;
...@@ -1581,16 +1581,23 @@ int READ_INFO::read_field() ...@@ -1581,16 +1581,23 @@ int READ_INFO::read_field()
} }
} }
#ifdef USE_MB #ifdef USE_MB
if (my_mbcharlen(read_charset, chr) > 1 && uint ml= my_mbcharlen(read_charset, chr);
to + my_mbcharlen(read_charset, chr) <= end_of_buff) if (ml == 0)
{
*to= '\0';
my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
read_charset->csname, buffer);
error= true;
return 1;
}
if (ml > 1 &&
to + ml <= end_of_buff)
{ {
uchar* p= to; uchar* p= to;
int ml, i;
*to++ = chr; *to++ = chr;
ml= my_mbcharlen(read_charset, chr); for (uint i= 1; i < ml; i++)
for (i= 1; i < ml; i++)
{ {
chr= GET; chr= GET;
if (chr == my_b_EOF) if (chr == my_b_EOF)
...@@ -1608,10 +1615,16 @@ int READ_INFO::read_field() ...@@ -1608,10 +1615,16 @@ int READ_INFO::read_field()
(const char *)p, (const char *)p,
(const char *)to)) (const char *)to))
continue; continue;
for (i= 0; i < ml; i++) for (uint i= 0; i < ml; i++)
PUSH(*--to); PUSH(*--to);
chr= GET; chr= GET;
} }
else if (ml > 1)
{
// Buffer is too small, exit while loop, and reallocate.
PUSH(chr);
break;
}
#endif #endif
*to++ = (uchar) chr; *to++ = (uchar) chr;
} }
...@@ -1855,7 +1868,15 @@ int READ_INFO::read_value(int delim, String *val) ...@@ -1855,7 +1868,15 @@ int READ_INFO::read_value(int delim, String *val)
for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;) for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;)
{ {
#ifdef USE_MB #ifdef USE_MB
if (my_mbcharlen(read_charset, chr) > 1) uint ml= my_mbcharlen(read_charset, chr);
if (ml == 0)
{
chr= my_b_EOF;
val->length(0);
return chr;
}
if (ml > 1)
{ {
DBUG_PRINT("read_xml",("multi byte")); DBUG_PRINT("read_xml",("multi byte"));
int i, ml= my_mbcharlen(read_charset, chr); int i, ml= my_mbcharlen(read_charset, chr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment