Skip to content

Commit a4ae3f2

Browse files
MDEV-36986: Support tracing array of primitive types
Json_writer had two separate code paths: add_unquoted_str() for numbers/bool/null, and add_escaped_str() which added the surrounding quotes itself for strings. Single_line_formatting_helper, which buffers consecutive array/object elements to decide if they fit on one line, assumed only strings could ever be buffered and always wrapped the flushed values in quotes. As a result, arrays of numbers (e.g. "depends_on_map_bits", "rec_per_key") were incorrectly rendered with their elements quoted as strings. Unify both paths into add_escaped_quoted_str(): the caller now hands over bytes that are already in their final on-the-wire form. String escaping (json_escape_to_string) writes its own surrounding quotes, while numbers/bool/null are passed through unquoted, so the one-line helper just concatenates the buffered payloads on flush instead of adding quotes itself. A DBUG_ASSERT in add_escaped_quoted_str() now checks that every payload is already a quoted string or a bare number/bool/null token, so a caller that violates the contract trips an assertion in debug builds instead of silently producing invalid JSON. Also: - Fix Json_writer_array::add(ulonglong)/(size_t), which went through add_ll() with a cast to longlong and corrupted large unsigned values (e.g. ULLONG_MAX); route them through add_ull() instead. - Fix mysql-test/include/opt_context_schema.inc: "subquery_runs" was nested inside the preceding object instead of being a sibling member, and "rec_per_key" items are now declared as "number" to match the corrected output. - Update recorded .result files for opt_trace, opt_context_*, and subselect_mat_analyze_json to reflect numbers/booleans no longer being quoted inside JSON arrays. - Extend unittest/sql/my_json_writer-t.cc with coverage for arrays of primitives: plain integers, mixed types, sizes, multi-line arrays, values flushed before a nested object, strings that were already escaped by the one-line buffer, and invalid utf8mb4 input through add_str(). - Rewrite the "multi-line array of integers" test to actually overflow the one-line buffer (9 seven-digit numbers instead of 7), since the previous version fit on one line and never exercised the element-per-line flush path it claimed to test. - Drop the now-redundant single-argument add_escaped_quoted_str() overload; all call sites already know their length. - Update json_escape_to_string()'s doc comments (my_json_writer.h, sql_json_lib.h) to state that it quotes its output, not just escapes it.
1 parent 3cdcd64 commit a4ae3f2

11 files changed

Lines changed: 272 additions & 100 deletions

‎mysql-test/include/opt_context_schema.inc‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ let $opt_context_schema=
4646
"rec_per_key": {
4747
"type": "array",
4848
"items": {
49-
"type": "string"
49+
"type": "number"
5050
}
5151
}
5252
},
@@ -197,13 +197,14 @@ let $opt_context_schema=
197197
"copy_cost"
198198
]
199199
}
200-
}
200+
},
201201
"subquery_runs": {
202202
"type": "array",
203203
"uniqueItems": true,
204204
"minItems": 1,
205205
"items": {
206206
"type": "number"
207+
}
207208
}
208209
},
209210
"required": [

‎mysql-test/main/join_outer_reorder.result‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ DEPS
6262
"row_may_be_null": true,
6363
"map_bit": 1,
6464
"depends_on_map_bits":
65-
["0"]
65+
[0]
6666
},
6767
{
6868
"table": "t2",
6969
"row_may_be_null": true,
7070
"map_bit": 2,
7171
"depends_on_map_bits":
72-
["0"]
72+
[0]
7373
}
7474
]
7575
]
@@ -103,14 +103,14 @@ DEPS
103103
"row_may_be_null": true,
104104
"map_bit": 1,
105105
"depends_on_map_bits":
106-
["0"]
106+
[0]
107107
},
108108
{
109109
"table": "t3",
110110
"row_may_be_null": true,
111111
"map_bit": 2,
112112
"depends_on_map_bits":
113-
["0"]
113+
[0]
114114
}
115115
]
116116
]
@@ -142,16 +142,16 @@ DEPS
142142
"row_may_be_null": true,
143143
"map_bit": 1,
144144
"depends_on_map_bits":
145-
["0"]
145+
[0]
146146
},
147147
{
148148
"table": "t3",
149149
"row_may_be_null": true,
150150
"map_bit": 2,
151151
"depends_on_map_bits":
152152
[
153-
"0",
154-
"1"
153+
0,
154+
1
155155
]
156156
}
157157
]
@@ -193,28 +193,28 @@ DEPS
193193
"row_may_be_null": true,
194194
"map_bit": 1,
195195
"depends_on_map_bits":
196-
["0"]
196+
[0]
197197
},
198198
{
199199
"table": "t4_2",
200200
"row_may_be_null": true,
201201
"map_bit": 2,
202202
"depends_on_map_bits":
203-
["0"]
203+
[0]
204204
},
205205
{
206206
"table": "t3",
207207
"row_may_be_null": true,
208208
"map_bit": 3,
209209
"depends_on_map_bits":
210-
["0"]
210+
[0]
211211
},
212212
{
213213
"table": "t4_3",
214214
"row_may_be_null": true,
215215
"map_bit": 4,
216216
"depends_on_map_bits":
217-
["0"]
217+
[0]
218218
}
219219
]
220220
]

‎mysql-test/main/opt_context_load_stats_basic.result‎

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].name');
278278
select * from t1 where a > 10;
279279
a b
280280
Warnings:
281-
Warning 4269 Failed to parse saved optimizer context: "name" element not present at offset 1583.
281+
Warning 4269 Failed to parse saved optimizer context: "name" element not present at offset 1575.
282282
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].ddl');
283283
select * from t1 where a > 10;
284284
a b
@@ -289,12 +289,12 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].file_stat_record
289289
select * from t1 where a > 10;
290290
a b
291291
Warnings:
292-
Warning 4269 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1576.
292+
Warning 4269 Failed to parse saved optimizer context: "file_stat_records" element not present at offset 1568.
293293
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].indexes[0].index_name');
294294
select * from t1 where a > 10;
295295
a b
296296
Warnings:
297-
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 211.
297+
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 209.
298298
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].indexes[0].rec_per_key');
299299
select * from t1 where a > 10;
300300
a b
@@ -304,37 +304,37 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read
304304
select * from t1 where a > 10;
305305
a b
306306
Warnings:
307-
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 744.
307+
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 736.
308308
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].ranges');
309309
select * from t1 where a > 10;
310310
a b
311311
Warnings:
312-
Warning 4269 Failed to parse saved optimizer context: "ranges" element not present at offset 736.
312+
Warning 4269 Failed to parse saved optimizer context: "ranges" element not present at offset 728.
313313
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].num_rows');
314314
select * from t1 where a > 10;
315315
a b
316316
Warnings:
317-
Warning 4269 Failed to parse saved optimizer context: "num_rows" element not present at offset 754.
317+
Warning 4269 Failed to parse saved optimizer context: "num_rows" element not present at offset 746.
318318
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].cost');
319319
select * from t1 where a > 10;
320320
a b
321321
Warnings:
322-
Warning 4269 Failed to parse saved optimizer context: "cost" element not present at offset 538.
322+
Warning 4269 Failed to parse saved optimizer context: "cost" element not present at offset 530.
323323
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].max_index_blocks');
324324
select * from t1 where a > 10;
325325
a b
326326
Warnings:
327-
Warning 4269 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 747.
327+
Warning 4269 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 739.
328328
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].max_row_blocks');
329329
select * from t1 where a > 10;
330330
a b
331331
Warnings:
332-
Warning 4269 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 749.
332+
Warning 4269 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 741.
333333
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].multi_range_read_info_const_calls[0].call_number');
334334
select * from t1 where a > 10;
335335
a b
336336
Warnings:
337-
Warning 4269 Failed to parse saved optimizer context: "call_number" element not present at offset 752.
337+
Warning 4269 Failed to parse saved optimizer context: "call_number" element not present at offset 744.
338338
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].indexes[0]');
339339
select * from t1 where a > 10;
340340
a b
@@ -376,51 +376,51 @@ set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_r
376376
select * from t1 where a > 10;
377377
a b
378378
Warnings:
379-
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 621.
379+
Warning 4269 Failed to parse saved optimizer context: "index_name" element not present at offset 613.
380380
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].num_records');
381381
select * from t1 where a > 10;
382382
a b
383383
Warnings:
384-
Warning 4269 Failed to parse saved optimizer context: "num_records" element not present at offset 629.
384+
Warning 4269 Failed to parse saved optimizer context: "num_records" element not present at offset 621.
385385
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].eq_ref');
386386
select * from t1 where a > 10;
387387
a b
388388
Warnings:
389-
Warning 4269 Failed to parse saved optimizer context: "eq_ref" element not present at offset 634.
389+
Warning 4269 Failed to parse saved optimizer context: "eq_ref" element not present at offset 626.
390390
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].index_cost_io');
391391
select * from t1 where a > 10;
392392
a b
393393
Warnings:
394-
Warning 4269 Failed to parse saved optimizer context: "index_cost_io" element not present at offset 627.
394+
Warning 4269 Failed to parse saved optimizer context: "index_cost_io" element not present at offset 619.
395395
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].index_cost_cpu');
396396
select * from t1 where a > 10;
397397
a b
398398
Warnings:
399-
Warning 4269 Failed to parse saved optimizer context: "index_cost_cpu" element not present at offset 616.
399+
Warning 4269 Failed to parse saved optimizer context: "index_cost_cpu" element not present at offset 608.
400400
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].row_cost_io');
401401
select * from t1 where a > 10;
402402
a b
403403
Warnings:
404-
Warning 4269 Failed to parse saved optimizer context: "row_cost_io" element not present at offset 629.
404+
Warning 4269 Failed to parse saved optimizer context: "row_cost_io" element not present at offset 621.
405405
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].row_cost_cpu');
406406
select * from t1 where a > 10;
407407
a b
408408
Warnings:
409-
Warning 4269 Failed to parse saved optimizer context: "row_cost_cpu" element not present at offset 618.
409+
Warning 4269 Failed to parse saved optimizer context: "row_cost_cpu" element not present at offset 610.
410410
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].max_index_blocks');
411411
select * from t1 where a > 10;
412412
a b
413413
Warnings:
414-
Warning 4269 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 624.
414+
Warning 4269 Failed to parse saved optimizer context: "max_index_blocks" element not present at offset 616.
415415
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].max_row_blocks');
416416
select * from t1 where a > 10;
417417
a b
418418
Warnings:
419-
Warning 4269 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 626.
419+
Warning 4269 Failed to parse saved optimizer context: "max_row_blocks" element not present at offset 618.
420420
set @opt_context=json_remove(@saved_opt_context_1, '$.tables[0].cost_for_index_read_calls[0].copy_cost');
421421
select * from t1 where a > 10;
422422
a b
423423
Warnings:
424-
Warning 4269 Failed to parse saved optimizer context: "copy_cost" element not present at offset 631.
424+
Warning 4269 Failed to parse saved optimizer context: "copy_cost" element not present at offset 623.
425425
drop table t1;
426426
drop database db1;

‎mysql-test/main/opt_context_store_stats.result‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ count(*)
5252
# === Tables
5353
# Tables in the context
5454
table_name file_stat_records index_name rec_per_key
55-
db1.t2 30 t2_idx_a ["5"]
55+
db1.t2 30 t2_idx_a [5]
5656
db1.t1 20 NULL NULL
5757
# === Range accesses
5858
index_name ranges num_rows max_index_blocks max_row_blocks
@@ -83,7 +83,7 @@ a b c
8383
# === Tables
8484
# Tables in the context
8585
table_name file_stat_records index_name rec_per_key
86-
db1.t2 30 t2_idx_a ["5"]
86+
db1.t2 30 t2_idx_a [5]
8787
db1.t1 20 NULL NULL
8888
# === Range accesses
8989
index_name ranges num_rows max_index_blocks max_row_blocks
@@ -114,7 +114,7 @@ insert into t1 (select t2.a as a, t2.a as b from t2);
114114
# === Tables
115115
# Tables in the context
116116
table_name file_stat_records index_name rec_per_key
117-
db1.t2 30 t2_idx_a ["5"]
117+
db1.t2 30 t2_idx_a [5]
118118
db1.t1 20 NULL NULL
119119
# === Range accesses
120120
index_name ranges num_rows max_index_blocks max_row_blocks
@@ -568,7 +568,7 @@ id select_type table type possible_keys key key_len ref rows Extra
568568
# === Tables
569569
# Tables in the context
570570
table_name file_stat_records index_name rec_per_key
571-
test.t1 3 a ["1"]
571+
test.t1 3 a [1]
572572
# === Range accesses
573573
index_name ranges num_rows max_index_blocks max_row_blocks
574574
# == End of optimizer context

‎mysql-test/main/opt_trace.result‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,7 +2700,7 @@ select t1.a from t1 left join t2 on t1.a=t2.a {
27002700
"table": "t2",
27012701
"row_may_be_null": true,
27022702
"map_bit": 1,
2703-
"depends_on_map_bits": ["0"]
2703+
"depends_on_map_bits": [0]
27042704
}
27052705
]
27062706
},
@@ -2856,7 +2856,7 @@ explain select * from t1 left join t2 on t2.a=t1.a {
28562856
"table": "t2",
28572857
"row_may_be_null": true,
28582858
"map_bit": 1,
2859-
"depends_on_map_bits": ["0"]
2859+
"depends_on_map_bits": [0]
28602860
}
28612861
]
28622862
},
@@ -3090,13 +3090,13 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
30903090
"table": "t2",
30913091
"row_may_be_null": true,
30923092
"map_bit": 1,
3093-
"depends_on_map_bits": ["0"]
3093+
"depends_on_map_bits": [0]
30943094
},
30953095
{
30963096
"table": "t3",
30973097
"row_may_be_null": true,
30983098
"map_bit": 2,
3099-
"depends_on_map_bits": ["0"]
3099+
"depends_on_map_bits": [0]
31003100
}
31013101
]
31023102
},

‎mysql-test/main/subselect_mat_analyze_json.result‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ ANALYZE
853853
"r_loops": 1,
854854
"r_partial_matches": 1,
855855
"r_partial_match_buffer_size": "REPLACED",
856-
"r_partial_match_array_sizes": ["4", "3"],
856+
"r_partial_match_array_sizes": [4, 3],
857857
"query_block": {
858858
"select_id": 2,
859859
"cost": "REPLACED",
@@ -1143,7 +1143,7 @@ ANALYZE
11431143
"r_loops": 1,
11441144
"r_partial_matches": 1,
11451145
"r_partial_match_buffer_size": "REPLACED",
1146-
"r_partial_match_array_sizes": ["4", "3"],
1146+
"r_partial_match_array_sizes": [4, 3],
11471147
"query_block": {
11481148
"select_id": 2,
11491149
"cost": "REPLACED",
@@ -1206,7 +1206,7 @@ ANALYZE
12061206
"r_loops": 1,
12071207
"r_partial_matches": 1,
12081208
"r_partial_match_buffer_size": "REPLACED",
1209-
"r_partial_match_array_sizes": ["4", "3"],
1209+
"r_partial_match_array_sizes": [4, 3],
12101210
"query_block": {
12111211
"select_id": 2,
12121212
"cost": "REPLACED",

0 commit comments

Comments
 (0)