maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #08860
Please review: MDEV-8433 Make field<'broken-string' use indexes
Hi Sergei,
Please review my patch for MDEV-8433.
I had doubts about one detail: how to make Field::store() that we're
currently creating a value for range search rather than regular doing a
INSERT/UPDATE.
I could think of two options:
1. Using sql_mode, similar to how temporal types pass MODE_INVALID_DATES.
2. Using a new parameter to this method:
int Field::store(const char *str, uint length, CHARSET_INFO *cs);
The former needed less changes, so I chose to use sql_mode.
But probably N2 would be better. Please suggest.
Thanks.
diff --git a/include/m_ctype.h b/include/m_ctype.h
index c5be24b..6ec74fe 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -313,6 +313,34 @@ typedef struct my_charset_loader_st
extern int (*my_string_stack_guard)(int);
+/*
+ A structure to return the statistics of a native string copying,
+ when no Unicode conversion is involved.
+
+ The stucture is OK to be unitialized before calling a copying routine.
+ A copying routine must populate the structure as follows:
+ - m_source_end_pos must be set by to a non-NULL value
+ in the range of the input string.
+ - m_well_formed_error_pos must be set to NULL if the string was
+ well formed, or to the position of the leftmost bad byte sequence.
+*/
+typedef struct
+{
+ const char *m_source_end_pos; /* Position where reading stopped */
+ const char *m_well_formed_error_pos; /* Position where a bad byte was found*/
+} MY_STRCOPY_STATUS;
+
+
+/*
+ A structure to return the statistics of a Unicode string conversion.
+*/
+typedef struct
+{
+ MY_STRCOPY_STATUS m_native_copy_status;
+ const char *m_cannot_convert_error_pos;
+} MY_STRCONV_STATUS;
+
+
/* See strings/CHARSET_INFO.txt for information about this structure */
struct my_collation_handler_st
{
@@ -349,6 +377,47 @@ struct my_collation_handler_st
void (*hash_sort)(CHARSET_INFO *cs, const uchar *key, size_t len,
ulong *nr1, ulong *nr2);
my_bool (*propagate)(CHARSET_INFO *cs, const uchar *str, size_t len);
+ /*
+ Create min and max keys for range search for WHERE field OP 'string',
+ where OP is a non-equality comparison operation (<,<=,=>,>).
+ Note, 'string' can be malformed. Bad bytes are replaced
+ to cs->min_sort_char by make_min_range and
+ to cs->max_sort_char by make_max_range.
+ The result of make_min_range() and make_max_range() is a well-formed
+ string.
+
+ Not more than "dst_length" bytes are copied to "dst".
+ Not more than "nchars" characters are copied to "dst".
+
+ If the result is big enough (i.e. no limitation happened neigher
+ on "dst_length" nor on "nchars"), then:
+ - the result of make_min_range() is less or equal to the original string
+ according to the collation "cs".
+ - the result of make_max_range() is greater or equal to the original string
+ according to the collation "cs".
+
+ TODO: Correct prefix key handing.
+ If the result does not fit the entire string (i.e. limitation happened
+ either on "dst_length" or on "nchars", e.g. in case of prefix keys),
+ then the result string is still well-formed, but:
+ - make_min_range() does not guarantee that its result is less or equal
+ to the original string
+ - make_max_range() does not guarantee that its result is greater or equal
+ to the original string
+ This is a bug and should be eventually fixed.
+ See:
+ - MDEV-8639 Bad result set when using prefix keys and characters less than space
+ - MDEV-8625 Bad result set with ignorable characters when using a prefix key
+ - MDEV-8626 Bad result set with expansions when using a prefix key
+ */
+ size_t (*make_min_range)(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status);
+ size_t (*make_max_range)(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status);
};
extern MY_COLLATION_HANDLER my_collation_8bit_bin_handler;
@@ -363,34 +432,6 @@ typedef int (*my_charset_conv_wc_mb)(CHARSET_INFO *, my_wc_t,
typedef size_t (*my_charset_conv_case)(CHARSET_INFO *,
char *, size_t, char *, size_t);
-/*
- A structure to return the statistics of a native string copying,
- when no Unicode conversion is involved.
-
- The stucture is OK to be unitialized before calling a copying routine.
- A copying routine must populate the structure as follows:
- - m_source_end_pos must be set by to a non-NULL value
- in the range of the input string.
- - m_well_formed_error_pos must be set to NULL if the string was
- well formed, or to the position of the leftmost bad byte sequence.
-*/
-typedef struct
-{
- const char *m_source_end_pos; /* Position where reading stopped */
- const char *m_well_formed_error_pos; /* Position where a bad byte was found*/
-} MY_STRCOPY_STATUS;
-
-
-/*
- A structure to return the statistics of a Unicode string conversion.
-*/
-typedef struct
-{
- MY_STRCOPY_STATUS m_native_copy_status;
- const char *m_cannot_convert_error_pos;
-} MY_STRCONV_STATUS;
-
-
/* See strings/CHARSET_INFO.txt about information on this structure */
struct my_charset_handler_st
{
@@ -496,7 +537,7 @@ struct my_charset_handler_st
MY_STRCOPY_STATUS *status);
/*
- copy_fix() - copy a string, replace bad bytes to '?'.
+ copy_fix() - copy a string, replace bad bytes to "replacement_character".
Not more than "nchars" characters are copied.
status->m_source_end_pos is set to a position in the range
@@ -510,7 +551,8 @@ struct my_charset_handler_st
size_t (*copy_fix)(CHARSET_INFO *,
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *status);
+ size_t nchars, MY_STRCOPY_STATUS *status,
+ my_wc_t replacement_character);
/**
Write a character to the target string, using its native code.
For Unicode character sets (utf8, ucs2, utf16, utf16le, utf32, filename)
@@ -660,11 +702,13 @@ extern uint my_instr_simple(CHARSET_INFO *,
size_t my_copy_8bit(CHARSET_INFO *,
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *);
+ size_t nchars, MY_STRCOPY_STATUS *,
+ my_wc_t replacement_character);
size_t my_copy_fix_mb(CHARSET_INFO *cs,
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *);
+ size_t nchars, MY_STRCOPY_STATUS *,
+ my_wc_t replacement_character);
/* Functions for 8bit */
extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *);
@@ -718,6 +762,25 @@ ulonglong my_strntoull10rnd_ucs2(CHARSET_INFO *cs,
void my_fill_8bit(CHARSET_INFO *cs, char* to, size_t l, int fill);
+
+size_t my_make_min_range_8bit(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *);
+size_t my_make_max_range_8bit(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *);
+
+size_t my_make_min_range_mb(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *);
+size_t my_make_max_range_mb(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *);
+
/* For 8-bit character set */
my_bool my_like_range_simple(CHARSET_INFO *cs,
const char *ptr, size_t ptr_length,
diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result
index c531aa2..5e33ba4 100644
--- a/mysql-test/r/ctype_uca.result
+++ b/mysql-test/r/ctype_uca.result
@@ -6567,7 +6567,7 @@ aÖ
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
@@ -6594,7 +6594,7 @@ Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
@@ -6627,25 +6627,29 @@ z
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
ALTER TABLE t1 DROP KEY ch;
# 0xD18F would be a good 2-byte character, 0xD1 is an incomplete sequence
SET @query=CONCAT('SELECT ch FROM t1 WHERE ch=''a', 0xD1,'''');
diff --git a/mysql-test/r/ctype_uca_innodb.result b/mysql-test/r/ctype_uca_innodb.result
index 8b507d9..eff50f5 100644
--- a/mysql-test/r/ctype_uca_innodb.result
+++ b/mysql-test/r/ctype_uca_innodb.result
@@ -103,9 +103,10 @@ aÖ
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
ch
a
@@ -127,12 +128,14 @@ aÐ
aÖ
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
ch
a
@@ -154,6 +157,7 @@ aÐ
aÖ
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 IGNORE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
@@ -163,25 +167,29 @@ z
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
ALTER TABLE t1 DROP KEY ch;
# 0xD18F would be a good 2-byte character, 0xD1 is an incomplete sequence
SET @query=CONCAT('SELECT ch FROM t1 WHERE ch=''a', 0xD1,'''');
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 216cea3..7f2b06d 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -5521,9 +5521,10 @@ aÖ
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
ch
a
@@ -5545,12 +5546,14 @@ aÐ
aÖ
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
ch
a
@@ -5572,6 +5575,7 @@ aÐ
aÖ
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 IGNORE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
@@ -5581,25 +5585,29 @@ z
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
ALTER TABLE t1 DROP KEY ch;
# 0xD18F would be a good 2-byte character, 0xD1 is an incomplete sequence
SET @query=CONCAT('SELECT ch FROM t1 WHERE ch=''a', 0xD1,'''');
@@ -5765,7 +5773,7 @@ aÖ
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'að' ORDER BY ch;
@@ -5792,7 +5800,7 @@ Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch<'aðb' ORDER BY ch;
@@ -5825,25 +5833,29 @@ z
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'að' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'ch' at row 1
EXPLAIN
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ch ch 182 NULL # Using where; Using index
+1 SIMPLE t1 range ch ch 182 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
SELECT ch FROM t1 FORCE KEY (ch) WHERE ch>'aðb' ORDER BY ch;
ch
z
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86b' for column 'ch' at row 1
ALTER TABLE t1 DROP KEY ch;
# 0xD18F would be a good 2-byte character, 0xD1 is an incomplete sequence
SET @query=CONCAT('SELECT ch FROM t1 WHERE ch=''a', 0xD1,'''');
@@ -10116,5 +10128,85 @@ Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = 10) and (`test`.`t1`.`a` = '1e1'))
DROP TABLE t1;
#
+# MDEV-8433 Make field<'broken-string' use indexes
+#
+SET NAMES 'utf8';
+CREATE TABLE t1 (
+id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+a varchar(60) COLLATE utf8_general_ci NOT NULL DEFAULT '',
+KEY(a)
+);
+INSERT INTO t1 (a) VALUES ('a0'),('a1'),('a2'),('a3');
+INSERT INTO t1 (a) VALUES ('b0'),('b1'),('b2'),('b3');
+INSERT INTO t1 (a) VALUES ('c0'),('c1'),('c2'),('c3');
+INSERT INTO t1 (a) VALUES ('d0'),('d1'),('d2'),('d3');
+INSERT INTO t1 (a) VALUES ('e0'),('e1'),('e2'),('e3');
+INSERT INTO t1 (a) VALUES ('v0'),('v1'),('v2'),('v3');
+INSERT INTO t1 (a) VALUES ('w0'),('w1'),('w2'),('w3');
+INSERT INTO t1 (a) VALUES ('x0'),('x1'),('x2'),('x3');
+INSERT INTO t1 (a) VALUES ('y0'),('y1'),('y2'),('y3');
+INSERT INTO t1 (a) VALUES ('z0'),('z1'),('z2'),('z3');
+EXPLAIN SELECT * FROM t1 WHERE a < 'bð';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 182 NULL 9 Using index condition
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+EXPLAIN SELECT * FROM t1 WHERE a <= 'bð';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 182 NULL 9 Using index condition
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+EXPLAIN SELECT * FROM t1 WHERE a > 'yð';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 182 NULL 9 Using index condition
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+EXPLAIN SELECT * FROM t1 WHERE a >= 'yð';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 182 NULL 9 Using index condition
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+SELECT * FROM t1 WHERE a < 'bð';
+id a
+1 a0
+2 a1
+3 a2
+4 a3
+5 b0
+6 b1
+7 b2
+8 b3
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+SELECT * FROM t1 WHERE a <= 'bð';
+id a
+1 a0
+2 a1
+3 a2
+4 a3
+5 b0
+6 b1
+7 b2
+8 b3
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+SELECT * FROM t1 WHERE a > 'yð';
+id a
+37 z0
+38 z1
+39 z2
+40 z3
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+SELECT * FROM t1 WHERE a >= 'yð';
+id a
+37 z0
+38 z1
+39 z2
+40 z3
+Warnings:
+Warning 1366 Incorrect string value: '\xF0\x9D\x8C\x86' for column 'a' at row 1
+DROP TABLE t1;
+#
# End of 10.1 tests
#
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index a7fb28c..3bbafef 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -2087,7 +2087,7 @@ Warning 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'fd' at row 1
# The following must not use range access:
explain select count(*) from t1 where fd <'ð';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ix_fd ix_fd 63 NULL # Using where; Using index
+1 SIMPLE t1 range ix_fd ix_fd 63 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'fd' at row 1
select count(*) from t1 where fd <'ð';
diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result
index 54dd300..91e601c 100644
--- a/mysql-test/r/range_mrr_icp.result
+++ b/mysql-test/r/range_mrr_icp.result
@@ -2089,7 +2089,7 @@ Warning 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'fd' at row 1
# The following must not use range access:
explain select count(*) from t1 where fd <'ð';
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index ix_fd ix_fd 63 NULL # Using where; Using index
+1 SIMPLE t1 range ix_fd ix_fd 63 NULL # Using where; Using index
Warnings:
Warning 1366 Incorrect string value: '\xF0\x9F\x98\x81' for column 'fd' at row 1
select count(*) from t1 where fd <'ð';
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index e89247d..95a6d23 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1818,6 +1818,34 @@ SELECT * FROM t1 WHERE (a,a)=(10,'1e1');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a,a)=(10,'1e1');
DROP TABLE t1;
+--echo #
+--echo # MDEV-8433 Make field<'broken-string' use indexes
+--echo #
+SET NAMES 'utf8';
+CREATE TABLE t1 (
+ id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ a varchar(60) COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ KEY(a)
+);
+INSERT INTO t1 (a) VALUES ('a0'),('a1'),('a2'),('a3');
+INSERT INTO t1 (a) VALUES ('b0'),('b1'),('b2'),('b3');
+INSERT INTO t1 (a) VALUES ('c0'),('c1'),('c2'),('c3');
+INSERT INTO t1 (a) VALUES ('d0'),('d1'),('d2'),('d3');
+INSERT INTO t1 (a) VALUES ('e0'),('e1'),('e2'),('e3');
+INSERT INTO t1 (a) VALUES ('v0'),('v1'),('v2'),('v3');
+INSERT INTO t1 (a) VALUES ('w0'),('w1'),('w2'),('w3');
+INSERT INTO t1 (a) VALUES ('x0'),('x1'),('x2'),('x3');
+INSERT INTO t1 (a) VALUES ('y0'),('y1'),('y2'),('y3');
+INSERT INTO t1 (a) VALUES ('z0'),('z1'),('z2'),('z3');
+EXPLAIN SELECT * FROM t1 WHERE a < 'bð';
+EXPLAIN SELECT * FROM t1 WHERE a <= 'bð';
+EXPLAIN SELECT * FROM t1 WHERE a > 'yð';
+EXPLAIN SELECT * FROM t1 WHERE a >= 'yð';
+SELECT * FROM t1 WHERE a < 'bð';
+SELECT * FROM t1 WHERE a <= 'bð';
+SELECT * FROM t1 WHERE a > 'yð';
+SELECT * FROM t1 WHERE a >= 'yð';
+DROP TABLE t1;
--echo #
--echo # End of 10.1 tests
diff --git a/sql/field.cc b/sql/field.cc
index 6ca0d4a..0fd12bf 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6302,6 +6302,52 @@ bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
** A string may be varchar or binary
****************************************************************************/
+/**
+ Copy a string (on INSERT/SET) or make a search range key.
+*/
+uint
+Field_longstr::Copier::well_formed_copy(THD *thd,
+ CHARSET_INFO *to_cs,
+ char *to, uint to_length,
+ CHARSET_INFO *from_cs,
+ const char *from, uint from_length,
+ uint nchars)
+{
+ if (use_native_copy(to_cs, from_cs))
+ {
+ m_cannot_convert_error_pos= NULL;
+ if (thd->variables.sql_mode & MODE_GET_MM_LEAF_GT)
+ {
+ /*
+ We're in range optimizer, e.g.:
+ SELECT * FROM t1 WHERE a>'string'
+ SELECT * FROM t1 WHERE a>='string'
+ */
+ return to_cs->coll->make_min_range(to_cs, to, to_length, from, from_length,
+ nchars, &m_native_copy_status);
+ }
+ else if (thd->variables.sql_mode & MODE_GET_MM_LEAF_LT)
+ {
+ /*
+ We're in range optimizer, e.g.:
+ SELECT * FROM t1 WHERE a<'string'
+ SELECT * FROM t1 WHERE a<='string'
+ */
+ return to_cs->coll->make_max_range(to_cs, to, to_length, from, from_length,
+ nchars, &m_native_copy_status);
+ }
+ else
+ {
+ // A regular INSERT or SET.
+ return to_cs->cset->copy_fix(to_cs, to, to_length, from, from_length,
+ nchars, &m_native_copy_status, '?');
+ }
+ }
+ return my_convert_fix(to_cs, to, to_length, from_cs, from, from_length,
+ nchars, this);
+}
+
+
/*
Report "not well formed" or "cannot convert" error
after storing a character string info a field.
@@ -6395,12 +6441,12 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
uint copy_length;
- String_copier copier;
+ Copier copier;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(!table || table->in_use == current_thd);
- copy_length= copier.well_formed_copy(field_charset,
+ copy_length= copier.well_formed_copy(get_thd(), field_charset,
(char*) ptr, field_length,
cs, from, length,
field_length / field_charset->mbmaxlen);
@@ -6949,9 +6995,9 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
uint copy_length;
- String_copier copier;
+ Copier copier;
- copy_length= copier.well_formed_copy(field_charset,
+ copy_length= copier.well_formed_copy(get_thd(), field_charset,
(char*) ptr + length_bytes,
field_length,
cs, from, length,
@@ -7418,7 +7464,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
uint copy_length, new_length;
- String_copier copier;
+ Copier copier;
const char *tmp;
char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
@@ -7467,9 +7513,9 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
bmove(ptr + packlength, (uchar*) &tmp, sizeof(char*));
return 0;
}
- copy_length= copier.well_formed_copy(field_charset,
+ copy_length= copier.well_formed_copy(get_thd(), field_charset,
(char*) value.ptr(), new_length,
- cs, from, length);
+ cs, from, length, length);
Field_blob::store_length(copy_length);
tmp= value.ptr();
bmove(ptr+packlength,(uchar*) &tmp,sizeof(char*));
diff --git a/sql/field.h b/sql/field.h
index 8c42195..aa83a10 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1194,6 +1194,19 @@ class Field_str :public Field {
class Field_longstr :public Field_str
{
protected:
+
+ /*
+ A String_copier extension that can create keys for the range optimizer.
+ */
+ class Copier: public String_copier
+ {
+ public:
+ uint well_formed_copy(THD *,
+ CHARSET_INFO *to_cs, char *to, uint to_length,
+ CHARSET_INFO *from_cs, const char *from,
+ uint from_length, uint nchars);
+ };
+
int report_if_important_data(const char *ptr, const char *end,
bool count_spaces);
bool check_string_copy_error(const String_copier *copier,
diff --git a/sql/item.cc b/sql/item.cc
index d14701d..a26e9be 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1293,7 +1293,8 @@ CHARSET_INFO *Item::default_charset()
for example in opt_range to adjust the key value to fit the column.
*/
-int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
+int Item::save_in_field_no_warnings(Field *field, bool no_conversions,
+ ulonglong sql_mode_add)
{
int res;
TABLE *table= field->table;
@@ -1302,7 +1303,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
ulonglong sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
- thd->variables.sql_mode|= MODE_INVALID_DATES;
+ thd->variables.sql_mode|= MODE_INVALID_DATES | sql_mode_add;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
res= save_in_field(field, no_conversions);
diff --git a/sql/item.h b/sql/item.h
index b611194..b0d0623 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -733,7 +733,8 @@ class Item: public Type_std_attributes
*/
virtual inline void quick_fix_field() { fixed= 1; }
/* Function returns 1 on overflow and -1 on fatal errors */
- int save_in_field_no_warnings(Field *field, bool no_conversions);
+ int save_in_field_no_warnings(Field *field, bool no_conversions,
+ ulonglong sql_mode_add= 0);
virtual int save_in_field(Field *field, bool no_conversions);
virtual void save_org_in_field(Field *field,
fast_field_copier data
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index af50fb8..7b12b65 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -7842,17 +7842,46 @@ Item_bool_func::get_mm_leaf(RANGE_OPT_PARAM *param,
*/
if (field->cmp_type() == STRING_RESULT && value->cmp_type() != STRING_RESULT)
goto end;
- err= value->save_in_field_no_warnings(field, 1);
+ ulonglong sql_mode_add;
+ switch (type) {
+ case LT_FUNC:
+ case LE_FUNC:
+ sql_mode_add= MODE_GET_MM_LEAF_LT;
+ break;
+ case GE_FUNC:
+ case GT_FUNC:
+ sql_mode_add= MODE_GET_MM_LEAF_GT;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ // Pass through
+ case EQ_FUNC:
+ case EQUAL_FUNC:
+ sql_mode_add= 0;
+ }
+ err= value->save_in_field_no_warnings(field, 1, sql_mode_add);
if (err == 2 && field->cmp_type() == STRING_RESULT)
{
if (type == EQ_FUNC || type == EQUAL_FUNC)
{
tree= new (alloc) SEL_ARG(field, 0, 0);
tree->type= SEL_ARG::IMPOSSIBLE;
+ goto end;
+ }
+ else
+ {
+ /*
+ Here we have Field_string, Field_varstring, or Field_blob
+ and a non-equality operation: LE_FUNC, LT_FUNC, GE_FUNC or GT_FUNC.
+ err==2 means that field->store(str, length, cs)
+ (that was called from value->save_in_field_no_warnings())
+ found some badly formed characters and replaced them
+ to min_sort_char (for GE_FUNC and GT_FUNC), or
+ to max_sort_char (for LE_FUNC and LT_FUNC).
+ Ignore the error and proceed with the SEL_ARG creation.
+ */
+ err= 0;
}
- else
- tree= NULL; /* Cannot infer anything */
- goto end;
}
if (err > 0)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index ae1d641..ceadecf 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -140,6 +140,9 @@ enum enum_binlog_row_image {
#define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30)
#define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31)
+#define MODE_GET_MM_LEAF_LT (1ULL << 32)
+#define MODE_GET_MM_LEAF_GT (1ULL << 33)
+
/* Bits for different old style modes */
#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0)
#define OLD_MODE_NO_PROGRESS_INFO (1 << 1)
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 379609a..1f88eda 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -908,14 +908,11 @@ String_copier::well_formed_copy(CHARSET_INFO *to_cs,
const char *from, uint from_length,
uint nchars)
{
- if ((to_cs == &my_charset_bin) ||
- (from_cs == &my_charset_bin) ||
- (to_cs == from_cs) ||
- my_charset_same(from_cs, to_cs))
+ if (use_native_copy(to_cs, from_cs))
{
m_cannot_convert_error_pos= NULL;
return to_cs->cset->copy_fix(to_cs, to, to_length, from, from_length,
- nchars, &m_native_copy_status);
+ nchars, &m_native_copy_status, '?');
}
return my_convert_fix(to_cs, to, to_length, from_cs, from, from_length,
nchars, this);
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 46188ce..b09c2cc 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -43,8 +43,24 @@ inline uint32 copy_and_convert(char *to, uint32 to_length,
}
-class String_copier: private MY_STRCONV_STATUS
+class String_copier: protected MY_STRCONV_STATUS
{
+protected:
+ /*
+ Check if it's possible to copy between two character sets
+ using native copy methods.
+ @param to_cs - character set to copy to
+ @param from_cs - character set to copy from
+ @return true if copying can use native copy routines
+ @return false if copying should use Unicode conversion routines
+ */
+ static bool use_native_copy(CHARSET_INFO *to_cs, CHARSET_INFO *from_cs)
+ {
+ return ((to_cs == &my_charset_bin) ||
+ (from_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs));
+ }
public:
const char *source_end_pos() const
{ return m_native_copy_status.m_source_end_pos; }
diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c
index d6a9695..19288b5 100644
--- a/strings/ctype-big5.c
+++ b/strings/ctype-big5.c
@@ -6795,7 +6795,9 @@ static MY_COLLATION_HANDLER my_collation_handler_big5_chinese_ci=
my_strcasecmp_mb,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -6811,7 +6813,9 @@ static MY_COLLATION_HANDLER my_collation_handler_big5_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 4d42973..2e7880a 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -498,7 +498,9 @@ MY_COLLATION_HANDLER my_collation_8bit_bin_handler =
my_strcasecmp_bin,
my_instr_bin,
my_hash_sort_8bit_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
@@ -514,7 +516,9 @@ static MY_COLLATION_HANDLER my_collation_binary_handler =
my_strcasecmp_bin,
my_instr_bin,
my_hash_sort_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c
index 9bf206f..a3de1ea 100644
--- a/strings/ctype-cp932.c
+++ b/strings/ctype-cp932.c
@@ -34670,7 +34670,9 @@ static MY_COLLATION_HANDLER my_collation_handler_cp932_japanese_ci=
my_strcasecmp_8bit,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -34686,7 +34688,9 @@ static MY_COLLATION_HANDLER my_collation_handler_cp932_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c
index 6603bc7..875ac82 100644
--- a/strings/ctype-czech.c
+++ b/strings/ctype-czech.c
@@ -619,7 +619,9 @@ static MY_COLLATION_HANDLER my_collation_latin2_czech_ci_handler =
my_strcasecmp_8bit,
my_instr_simple,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
struct charset_info_st my_charset_latin2_czech_ci =
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index 1f13ab6..55eb437 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -9964,7 +9964,9 @@ static MY_COLLATION_HANDLER my_collation_handler_euckr_korean_ci=
my_strcasecmp_mb,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -9980,7 +9982,9 @@ static MY_COLLATION_HANDLER my_collation_handler_euckr_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c
index 82c4bb5..69893db 100644
--- a/strings/ctype-eucjpms.c
+++ b/strings/ctype-eucjpms.c
@@ -67497,7 +67497,9 @@ static MY_COLLATION_HANDLER my_collation_eucjpms_japanese_ci_handler =
my_strcasecmp_mb,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -67513,7 +67515,9 @@ static MY_COLLATION_HANDLER my_collation_eucjpms_bin_handler =
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c
index b0e275f..c4beb9f 100644
--- a/strings/ctype-gb2312.c
+++ b/strings/ctype-gb2312.c
@@ -6367,7 +6367,9 @@ static MY_COLLATION_HANDLER my_collation_handler_gb2312_chinese_ci=
my_strcasecmp_mb, /* instr */
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -6383,7 +6385,9 @@ static MY_COLLATION_HANDLER my_collation_handler_gb2312_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c
index 37b003f..d4c6c45 100644
--- a/strings/ctype-gbk.c
+++ b/strings/ctype-gbk.c
@@ -10679,7 +10679,9 @@ static MY_COLLATION_HANDLER my_collation_handler_gbk_chinese_ci=
my_strcasecmp_mb,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -10695,7 +10697,9 @@ static MY_COLLATION_HANDLER my_collation_handler_gbk_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c
index 8bc3ac3..1fd20a5 100644
--- a/strings/ctype-latin1.c
+++ b/strings/ctype-latin1.c
@@ -729,7 +729,9 @@ static MY_COLLATION_HANDLER my_collation_german2_ci_handler=
my_strcasecmp_8bit,
my_instr_simple,
my_hash_sort_latin1_de,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c
index eef283d..7c7fdb5 100644
--- a/strings/ctype-mb.c
+++ b/strings/ctype-mb.c
@@ -441,7 +441,8 @@ my_append_fix_badly_formed_tail(CHARSET_INFO *cs,
char *to, char *to_end,
const char *from, const char *from_end,
size_t nchars,
- MY_STRCOPY_STATUS *status)
+ MY_STRCOPY_STATUS *status,
+ my_wc_t replacement_character)
{
char *to0= to;
@@ -475,7 +476,8 @@ my_append_fix_badly_formed_tail(CHARSET_INFO *cs,
if (!status->m_well_formed_error_pos)
status->m_well_formed_error_pos= from;
- if ((chlen= cs->cset->wc_mb(cs, '?', (uchar*) to, (uchar *) to_end)) <= 0)
+ if ((chlen= cs->cset->wc_mb(cs, replacement_character,
+ (uchar*) to, (uchar *) to_end)) <= 0)
break; /* Question mark does not fit into the destination */
to+= chlen;
from++;
@@ -490,7 +492,8 @@ size_t
my_copy_fix_mb(CHARSET_INFO *cs,
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *status)
+ size_t nchars, MY_STRCOPY_STATUS *status,
+ my_wc_t replacement_character)
{
size_t well_formed_nchars;
size_t well_formed_length;
@@ -511,11 +514,34 @@ my_copy_fix_mb(CHARSET_INFO *cs,
src + well_formed_length,
src + src_length,
nchars - well_formed_nchars,
- status);
+ status,
+ replacement_character);
return well_formed_length + fixed_length;
}
+size_t
+my_make_min_range_mb(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status)
+{
+ return cs->cset->copy_fix(cs, dst, dst_length, src, src_length, nchars,
+ status, cs->min_sort_char);
+}
+
+
+size_t
+my_make_max_range_mb(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status)
+{
+ return cs->cset->copy_fix(cs, dst, dst_length, src, src_length, nchars,
+ status, cs->max_sort_char);
+}
+
+
uint my_instr_mb(CHARSET_INFO *cs,
const char *b, size_t b_length,
const char *s, size_t s_length,
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 020bfd0..793a401 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -1135,7 +1135,8 @@ size_t
my_copy_8bit(CHARSET_INFO *cs __attribute__((unused)),
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *status)
+ size_t nchars, MY_STRCOPY_STATUS *status,
+ my_wc_t replacement_character __attribute__((unused)))
{
set_if_smaller(src_length, dst_length);
set_if_smaller(src_length, nchars);
@@ -1146,6 +1147,25 @@ my_copy_8bit(CHARSET_INFO *cs __attribute__((unused)),
return src_length;
}
+size_t
+my_make_min_range_8bit(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status)
+{
+ return my_copy_8bit(cs, dst, dst_length, src, src_length, nchars, status, 0);
+}
+
+
+size_t
+my_make_max_range_8bit(CHARSET_INFO *cs,
+ char *dst, size_t dst_length,
+ const char *src, size_t src_length,
+ size_t nchars, MY_STRCOPY_STATUS *status)
+{
+ return my_copy_8bit(cs, dst, dst_length, src, src_length, nchars, status, 0);
+}
+
size_t my_lengthsp_8bit(CHARSET_INFO *cs __attribute__((unused)),
const char *ptr, size_t length)
@@ -1965,5 +1985,7 @@ MY_COLLATION_HANDLER my_collation_8bit_simple_ci_handler =
my_strcasecmp_8bit,
my_instr_simple,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c
index 629e1cd..45da0ee 100644
--- a/strings/ctype-sjis.c
+++ b/strings/ctype-sjis.c
@@ -34049,7 +34049,9 @@ static MY_COLLATION_HANDLER my_collation_handler_sjis_japanese_ci=
my_strcasecmp_8bit,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -34065,7 +34067,9 @@ static MY_COLLATION_HANDLER my_collation_handler_sjis_bin=
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c
index c62e588..e28c99a 100644
--- a/strings/ctype-tis620.c
+++ b/strings/ctype-tis620.c
@@ -854,7 +854,9 @@ static MY_COLLATION_HANDLER my_collation_ci_handler =
my_strcasecmp_8bit,
my_instr_simple, /* QQ: To be fixed */
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};
static MY_CHARSET_HANDLER my_charset_handler=
diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c
index 60bd96e..a15f1ca 100644
--- a/strings/ctype-uca.c
+++ b/strings/ctype-uca.c
@@ -22923,7 +22923,9 @@ MY_COLLATION_HANDLER my_collation_ucs2_uca_handler =
NULL,
my_instr_mb,
my_hash_sort_ucs2_uca,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
struct charset_info_st my_charset_ucs2_unicode_ci=
@@ -23786,7 +23788,9 @@ MY_COLLATION_HANDLER my_collation_any_uca_handler =
NULL,
my_instr_mb,
my_hash_sort_any_uca,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
/*
@@ -25524,7 +25528,9 @@ MY_COLLATION_HANDLER my_collation_utf32_uca_handler =
NULL,
my_instr_mb,
my_hash_sort_any_uca,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
extern MY_CHARSET_HANDLER my_charset_utf32_handler;
@@ -26387,7 +26393,9 @@ MY_COLLATION_HANDLER my_collation_utf16_uca_handler =
NULL,
my_instr_mb,
my_hash_sort_any_uca,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
extern MY_CHARSET_HANDLER my_charset_utf16_handler;
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index e7ba5cb..4d7c08f 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -172,14 +172,16 @@ static size_t
my_copy_fix_mb2_or_mb4(CHARSET_INFO *cs,
char *dst, size_t dst_length,
const char *src, size_t src_length,
- size_t nchars, MY_STRCOPY_STATUS *status)
+ size_t nchars, MY_STRCOPY_STATUS *status,
+ my_wc_t replacement_character)
{
size_t length2, src_offset= src_length % cs->mbminlen;
my_char_copy_status_t padstatus;
if (!src_offset)
return my_copy_fix_mb(cs, dst, dst_length,
- src, src_length, nchars, status);
+ src, src_length, nchars, status,
+ replacement_character);
if ((padstatus= my_copy_incomplete_char(cs, dst, dst_length,
src, src_length, nchars, TRUE)) ==
MY_CHAR_COPY_ERROR)
@@ -189,7 +191,7 @@ my_copy_fix_mb2_or_mb4(CHARSET_INFO *cs,
}
length2= my_copy_fix_mb(cs, dst + cs->mbminlen, dst_length - cs->mbminlen,
src + src_offset, src_length - src_offset,
- nchars - 1, status);
+ nchars - 1, status, replacement_character);
if (padstatus == MY_CHAR_COPY_FIXED)
status->m_well_formed_error_pos= src;
return cs->mbminlen /* The left-padded character */ + length2;
@@ -1538,7 +1540,9 @@ static MY_COLLATION_HANDLER my_collation_utf16_general_ci_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf16,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -1554,7 +1558,9 @@ static MY_COLLATION_HANDLER my_collation_utf16_bin_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf16_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -1761,7 +1767,9 @@ static MY_COLLATION_HANDLER my_collation_utf16le_general_ci_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf16,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -1777,7 +1785,9 @@ static MY_COLLATION_HANDLER my_collation_utf16le_bin_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf16_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -2506,7 +2516,9 @@ static MY_COLLATION_HANDLER my_collation_utf32_general_ci_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf32,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -2522,7 +2534,9 @@ static MY_COLLATION_HANDLER my_collation_utf32_bin_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_utf32,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -2993,7 +3007,9 @@ static MY_COLLATION_HANDLER my_collation_ucs2_general_ci_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_ucs2,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -3009,7 +3025,9 @@ static MY_COLLATION_HANDLER my_collation_ucs2_bin_handler =
my_strcasecmp_mb2_or_mb4,
my_instr_mb,
my_hash_sort_ucs2_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
index 308f5f0..850b2ff 100644
--- a/strings/ctype-ujis.c
+++ b/strings/ctype-ujis.c
@@ -67241,7 +67241,9 @@ static MY_COLLATION_HANDLER my_collation_ujis_japanese_ci_handler =
my_strcasecmp_mb,
my_instr_mb,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -67257,7 +67259,9 @@ static MY_COLLATION_HANDLER my_collation_ujis_bin_handler =
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 3c2c812..137a813 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -5459,7 +5459,9 @@ static MY_COLLATION_HANDLER my_collation_utf8_general_ci_handler =
my_strcasecmp_utf8,
my_instr_mb,
my_hash_sort_utf8,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -5475,7 +5477,9 @@ static MY_COLLATION_HANDLER my_collation_utf8_general_mysql500_ci_handler =
my_strcasecmp_utf8,
my_instr_mb,
my_hash_sort_utf8,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -5491,7 +5495,9 @@ static MY_COLLATION_HANDLER my_collation_utf8_bin_handler =
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
MY_CHARSET_HANDLER my_charset_utf8_handler=
@@ -5775,7 +5781,9 @@ static MY_COLLATION_HANDLER my_collation_cs_handler =
my_strcasecmp_utf8,
my_instr_mb,
my_hash_sort_utf8,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
struct charset_info_st my_charset_utf8_general_cs=
@@ -7075,7 +7083,9 @@ static MY_COLLATION_HANDLER my_collation_filename_handler =
my_strcasecmp_utf8,
my_instr_mb,
my_hash_sort_utf8,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
static MY_CHARSET_HANDLER my_charset_filename_handler=
@@ -7829,7 +7839,9 @@ static MY_COLLATION_HANDLER my_collation_utf8mb4_general_ci_handler=
my_strcasecmp_utf8mb4,
my_instr_mb,
my_hash_sort_utf8mb4,
- my_propagate_complex
+ my_propagate_complex,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
@@ -7845,7 +7857,9 @@ static MY_COLLATION_HANDLER my_collation_utf8mb4_bin_handler =
my_strcasecmp_mb_bin,
my_instr_mb,
my_hash_sort_mb_bin,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_mb,
+ my_make_max_range_mb,
};
diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c
index 27e6a94..55022b2 100644
--- a/strings/ctype-win1250ch.c
+++ b/strings/ctype-win1250ch.c
@@ -683,7 +683,9 @@ static MY_COLLATION_HANDLER my_collation_czech_ci_handler =
my_strcasecmp_8bit,
my_instr_simple,
my_hash_sort_simple,
- my_propagate_simple
+ my_propagate_simple,
+ my_make_min_range_8bit,
+ my_make_max_range_8bit,
};