Skip to content

Commit a924ecc

Browse files
MDEV-39412: parse error reading tabs in ranges
Note: while reading from information_schema.optimizer_context one level of unescaping is already done i.e. (\\t becomes \t or \\\\t becomes \\t) w.r.t the MDEV, there are 2 problems: - 1. When reading from the sql script file, json parser is not able to parse the range value in json_read_value() from json_lib.c "ranges": [ "(b\t\t\t\t\t\t) <= (b) <= (b???????)" ], mainly the \t\t stuff, and hence a warning. It also stops loading the context into memory. Since, a new table is created with empty data, and without context, we get Impossible WHERE noticed after reading const tables 2. There is unescaping call being made in read_string() from sql_json_lib.cc while parsing of the context. With this \\t was becoming \t. However, print_range() from opt_range.cc already does escaping of the values. The value "b\t\t\t" was in fact produced as "\b\\t\\t\\t". Later, we try to compare range values from the query and the context. Here a mismatch a found because, in one case there was escaping, and in the other case escaping got removed. Solutions ========= For Problem 1. have escaping for ranges. This should be done while dumping range values into the context. For Problem 2. Remove unscaping call in read_string().
1 parent 5d1fb08 commit a924ecc

5 files changed

Lines changed: 86 additions & 20 deletions

File tree

mysql-test/main/opt_context_replay_basic.result

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,4 +295,33 @@ id select_type table type possible_keys key key_len ref rows Extra
295295
1 SIMPLE NULL NULL NULL NULL NULL NULL 3 Deleting all rows
296296
set optimizer_replay_context='';
297297
drop table t1;
298+
#
299+
# MDEV-39412: Failed to parse saved optimizer context: error reading ranges value
300+
#
301+
set optimizer_record_context=0;
302+
CREATE TABLE t1(
303+
a VARCHAR(8),
304+
b VARCHAR(8),
305+
KEY(A),
306+
KEY(B)
307+
);
308+
INSERT INTO t1 SELECT REPEAT('a',8), REPEAT('b',8) FROM seq_1_to_10;
309+
set optimizer_record_context=1;
310+
EXPLAIN
311+
SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
312+
ORDER BY a,b;
313+
id select_type table type possible_keys key key_len ref rows Extra
314+
1 SIMPLE t1 index_merge a,b a,b 35,35 NULL 10 Using sort_union(a,b); Using where; Using filesort
315+
select context into dumpfile "../../tmp/dump1.sql"
316+
from information_schema.optimizer_context;
317+
drop table t1;
318+
set optimizer_replay_context='opt_context';
319+
# Same query as above, must have same explain:
320+
EXPLAIN
321+
SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
322+
ORDER BY a,b;
323+
id select_type table type possible_keys key key_len ref rows Extra
324+
1 SIMPLE t1 index_merge a,b a,b 35,35 NULL 10 Using sort_union(a,b); Using where; Using filesort
325+
set optimizer_replay_context='';
326+
drop table t1;
298327
drop database db1;

mysql-test/main/opt_context_replay_basic.test

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,41 @@ set optimizer_replay_context='';
147147
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
148148
drop table t1;
149149

150+
--echo #
151+
--echo # MDEV-39412: Failed to parse saved optimizer context: error reading ranges value
152+
--echo #
153+
set optimizer_record_context=0;
154+
155+
CREATE TABLE t1(
156+
a VARCHAR(8),
157+
b VARCHAR(8),
158+
KEY(A),
159+
KEY(B)
160+
);
161+
INSERT INTO t1 SELECT REPEAT('a',8), REPEAT('b',8) FROM seq_1_to_10;
162+
163+
set optimizer_record_context=1;
164+
EXPLAIN
165+
SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
166+
ORDER BY a,b;
167+
168+
select context into dumpfile "../../tmp/dump1.sql"
169+
from information_schema.optimizer_context;
170+
drop table t1;
171+
172+
--disable_query_log
173+
--disable_result_log
174+
--source "$MYSQLTEST_VARDIR/tmp/dump1.sql"
175+
--enable_query_log
176+
--enable_result_log
177+
set optimizer_replay_context='opt_context';
178+
--echo # Same query as above, must have same explain:
179+
EXPLAIN
180+
SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
181+
ORDER BY a,b;
182+
183+
set optimizer_replay_context='';
184+
--remove_file "$MYSQLTEST_VARDIR/tmp/dump1.sql"
185+
drop table t1;
186+
150187
drop database db1;

sql/opt_context_store_replay.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,18 @@ void dump_mrr_info_calls(List<Multi_range_read_const_call_record> *mrr_list,
256256
Json_writer_object irc_wrapper(ctx_writer);
257257
irc_wrapper.add("index_name", irc->idx_name);
258258

259+
List_iterator rc_li(irc->range_list);
260+
Json_writer_array ranges_wrapper(ctx_writer, "ranges");
261+
while (const char *range_str= rc_li++)
259262
{
260-
Json_writer_array ranges_wrapper(ctx_writer, "ranges");
261-
List_iterator rc_li(irc->range_list);
262-
while (const char *range_str= rc_li++)
263-
ranges_wrapper.add(range_str, strlen(range_str));
263+
const String range_info(range_str, strlen(range_str),
264+
system_charset_info);
265+
StringBuffer<128> escaped_range_info;
266+
json_escape_to_string(&range_info, &escaped_range_info);
267+
ranges_wrapper.add(escaped_range_info.c_ptr_safe(),
268+
escaped_range_info.length());
264269
}
270+
ranges_wrapper.end();
265271

266272
irc_wrapper.add("num_rows", irc->rows);
267273
{

sql/sql_json_lib.cc

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,7 @@ bool read_string(MEM_ROOT *mem_root, json_engine_t *je, const char *read_elem_ke
7878
if (check_reading_of_elem_key(je, read_elem_key, err_buf))
7979
return true;
8080

81-
StringBuffer<128> val_buf;
82-
if (json_unescape_to_string((const char *) je->value, je->value_len,
83-
&val_buf))
84-
{
85-
err_buf->append(STRING_WITH_LEN("un-escaping error of "));
86-
err_buf->append(read_elem_key, strlen(read_elem_key));
87-
err_buf->append(STRING_WITH_LEN(" element"));
88-
return true;
89-
}
90-
91-
value= strdup_root(mem_root, val_buf.c_ptr_safe());
81+
value= strmake_root(mem_root, (const char *) je->value, je->value_len);
9282
return false;
9383
}
9484

unittest/sql/json_reader-t.cc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,29 @@ int main(int args, char **argv)
3939
MEM_ROOT alloc;
4040
json_engine_t je;
4141
int rc;
42+
const char *esc_str_val= "a\\bc";
4243
init_alloc_root(0, &alloc, 32768, 0, 0);
4344
mem_root_dynamic_array_init(&alloc, 0, &je.stack,
4445
sizeof(int), NULL, JSON_DEPTH_DEFAULT,
4546
JSON_DEPTH_INC, MYF(0));
4647
system_charset_info= &my_charset_utf8mb3_bin;
47-
const char *js_doc="{ \"str_val\": \"abc\", \"double_val\": 1234.5 }";
48+
const char *js_doc= "{ \"str_val\": \"abc\", \"double_val\": 1234.5, "
49+
"\"esc_str_val\": \"a\\bc\" }";
4850
json_scan_start(&je, &my_charset_utf8mb3_bin, (const uchar *) js_doc,
4951
(const uchar *) js_doc + strlen(js_doc));
5052

5153
char *parsed_name;
5254
double parsed_dbl;
55+
char *parsed_esc_str;
5356
Read_named_member array[]= {
54-
{"str_val", Read_string(&alloc, &parsed_name), false},
57+
{"str_val", Read_string(&alloc, &parsed_name), false},
5558
{"double_val", Read_double(&parsed_dbl), false},
56-
{NULL, Read_double(NULL), false }
57-
};
59+
{"esc_str_val", Read_string(&alloc, &parsed_esc_str), false},
60+
{NULL, Read_double(NULL), false}};
5861
String err_buf;
5962

60-
rc= json_read_object(&je, array, &err_buf);
63+
rc= json_read_object(&je, array, &err_buf) ||
64+
strcmp(parsed_esc_str, esc_str_val);
6165
ok(!rc, "Basic object read");
6266
free_root(&alloc, 0);
6367
#if 0

0 commit comments

Comments
 (0)