@@ -94,8 +94,8 @@ class Histogram_json_builder : public Histogram_builder
94
94
{
95
95
column->store_field_value ((uchar*) elem, col_length);
96
96
StringBuffer<MAX_FIELD_WIDTH> val;
97
- column->val_str (&val);
98
- writer.add_member (" end" ).add_str (val. c_ptr ());
97
+ String *str= column->val_str (&val);
98
+ writer.add_member (" end" ).add_str (str-> c_ptr_safe ());
99
99
finalize_bucket ();
100
100
}
101
101
@@ -109,10 +109,10 @@ class Histogram_json_builder : public Histogram_builder
109
109
DBUG_ASSERT (bucket.size == 0 );
110
110
column->store_field_value ((uchar*) elem, col_length);
111
111
StringBuffer<MAX_FIELD_WIDTH> val;
112
- column->val_str (&val);
112
+ String *str= column->val_str (&val);
113
113
114
114
writer.start_object ();
115
- writer.add_member (" start" ).add_str (val. c_ptr ());
115
+ writer.add_member (" start" ).add_str (str-> c_ptr_safe ());
116
116
117
117
bucket.ndv = 1 ;
118
118
bucket.size = cnt;
@@ -264,14 +264,17 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
264
264
const char *err;
265
265
DBUG_ENTER (" Histogram_json_hb::parse" );
266
266
DBUG_ASSERT (type_arg == JSON_HB);
267
+ const char *err_pos= hist_data;
267
268
const char *obj1;
268
269
int obj1_len;
269
270
double cumulative_size= 0.0 ;
271
+ size_t end_member_index= (size_t )-1 ;
270
272
271
273
if (JSV_OBJECT != json_type (hist_data, hist_data + hist_data_len,
272
274
&obj1, &obj1_len))
273
275
{
274
276
err= " Root JSON element must be a JSON object" ;
277
+ err_pos= hist_data;
275
278
goto error;
276
279
}
277
280
@@ -281,6 +284,7 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
281
284
" histogram_hb_v2" , &hist_array,
282
285
&hist_array_len))
283
286
{
287
+ err_pos= obj1;
284
288
err= " A JSON array expected" ;
285
289
goto error;
286
290
}
@@ -296,11 +300,13 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
296
300
break ;
297
301
if (ret == JSV_BAD_JSON)
298
302
{
303
+ err_pos= hist_array;
299
304
err= " JSON parse error" ;
300
305
goto error;
301
306
}
302
307
if (ret != JSV_OBJECT)
303
308
{
309
+ err_pos= hist_array;
304
310
err= " Object expected" ;
305
311
goto error;
306
312
}
@@ -313,6 +319,7 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
313
319
" start" , &val, &val_len);
314
320
if (ret != JSV_STRING && ret != JSV_NUMBER)
315
321
{
322
+ err_pos= bucket_info;
316
323
err= " .start member must be present and be a scalar" ;
317
324
goto error;
318
325
}
@@ -324,6 +331,7 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
324
331
" size" , &size, &size_len);
325
332
if (ret != JSV_NUMBER)
326
333
{
334
+ err_pos= bucket_info;
327
335
err= " .size member must be present and be a scalar" ;
328
336
goto error;
329
337
}
@@ -333,6 +341,7 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
333
341
double size_d= my_strtod (size, &size_end, &conv_err);
334
342
if (conv_err)
335
343
{
344
+ err_pos= size;
336
345
err= " .size member must be a floating-point value" ;
337
346
goto error;
338
347
}
@@ -345,48 +354,66 @@ bool Histogram_json_hb::parse(MEM_ROOT *mem_root, Field *field,
345
354
" ndv" , &ndv, &ndv_len);
346
355
if (ret != JSV_NUMBER)
347
356
{
357
+ err_pos= bucket_info;
348
358
err= " .ndv member must be present and be a scalar" ;
349
359
goto error;
350
360
}
351
361
char *ndv_end= (char *)ndv + ndv_len;
352
362
longlong ndv_ll= my_strtoll10 (ndv, &ndv_end, &conv_err);
353
363
if (conv_err)
354
364
{
365
+ err_pos= ndv;
355
366
err= " .ndv member must be an integer value" ;
356
367
goto error;
357
368
}
358
369
370
+
371
+ uchar buf[MAX_KEY_LENGTH];
372
+ uint len_to_copy= field->key_length ();
373
+ field->store_text (val, val_len, &my_charset_bin);
374
+ uint bytes= field->get_key_image (buf, len_to_copy, Field::itRAW);
375
+
376
+ buckets.push_back ({std::string ((char *)buf, bytes), cumulative_size,
377
+ ndv_ll});
378
+
379
+ // Read the "end" field
359
380
const char *end_val;
360
381
int end_val_len;
361
382
ret= json_get_object_key (bucket_info, bucket_info+bucket_info_len,
362
383
" end" , &end_val, &end_val_len);
363
384
if (ret != JSV_NOTHING && ret != JSV_STRING && ret !=JSV_NUMBER)
364
385
{
386
+ err_pos= bucket_info;
365
387
err= " .end member must be a scalar" ;
366
388
goto error;
367
389
}
368
390
if (ret != JSV_NOTHING)
369
- last_bucket_end_endp.assign (end_val, end_val_len);
370
-
371
- buckets.push_back ({std::string (val, val_len), NULL , cumulative_size,
372
- ndv_ll});
373
-
374
- if (buckets.size ())
375
391
{
376
- auto & prev_bucket= buckets[buckets. size ()- 1 ] ;
377
- if (prev_bucket. ndv == 1 )
378
- prev_bucket. end_value = &prev_bucket. start_value ;
379
- else
380
- prev_bucket. end_value = & buckets.back (). start_value ;
392
+ field-> store_text (end_val, end_val_len, &my_charset_bin) ;
393
+ uint bytes= field-> get_key_image (buf, len_to_copy, Field::itRAW);
394
+ last_bucket_end_endp. assign (( char *)buf, bytes) ;
395
+ if (end_member_index == ( size_t )- 1 )
396
+ end_member_index= buckets.size () ;
381
397
}
382
398
}
383
- buckets.back ().end_value = &last_bucket_end_endp;
384
399
size= buckets.size ();
385
400
401
+ if (end_member_index != buckets.size ())
402
+ {
403
+ err= " .end must be present in the last bucket and only there" ;
404
+ err_pos= hist_data;
405
+ goto error;
406
+ }
407
+ if (!buckets.size ())
408
+ {
409
+ err= " .end member is allowed only in last bucket" ;
410
+ err_pos= hist_data;
411
+ goto error;
412
+ }
413
+
386
414
DBUG_RETURN (false );
387
415
error:
388
- my_error (ER_JSON_HISTOGRAM_PARSE_FAILED, MYF (0 ), err,
389
- 12345 );
416
+ my_error (ER_JSON_HISTOGRAM_PARSE_FAILED, MYF (0 ), err, err_pos - hist_data);
390
417
DBUG_RETURN (true );
391
418
}
392
419
@@ -469,7 +496,7 @@ double Histogram_json_hb::point_selectivity(Field *field, key_range *endpoint,
469
496
* The bucket has one value and this is the value we are looking for.
470
497
* The bucket has multiple values. Then, assume
471
498
*/
472
- sel= (get_left_fract (idx) - buckets[idx].cum_fract ) / buckets[idx].ndv ;
499
+ sel= (buckets[idx].cum_fract - get_left_fract (idx) ) / buckets[idx].ndv ;
473
500
}
474
501
return sel;
475
502
}
@@ -483,6 +510,14 @@ double Histogram_json_hb::get_left_fract(int idx)
483
510
return buckets[idx-1 ].cum_fract ;
484
511
}
485
512
513
+ std::string& Histogram_json_hb::get_end_value (int idx)
514
+ {
515
+ if (idx == (int )buckets.size ()-1 )
516
+ return last_bucket_end_endp;
517
+ else
518
+ return buckets[idx+1 ].start_value ;
519
+ }
520
+
486
521
/*
487
522
@param field The table field histogram is for. We don't care about the
488
523
field's current value, we only need its virtual functions to
@@ -514,7 +549,7 @@ double Histogram_json_hb::range_selectivity(Field *field, key_range *min_endp,
514
549
double left_fract= get_left_fract (idx);
515
550
double sel= position_in_interval (field, min_key, min_key_len,
516
551
buckets[idx].start_value ,
517
- *buckets[ idx]. end_value );
552
+ get_end_value ( idx) );
518
553
519
554
min= left_fract + sel * (buckets[idx].cum_fract - left_fract);
520
555
}
@@ -538,7 +573,7 @@ double Histogram_json_hb::range_selectivity(Field *field, key_range *min_endp,
538
573
double left_fract= get_left_fract (idx);
539
574
double sel= position_in_interval (field, max_key, max_key_len,
540
575
buckets[idx].start_value ,
541
- *buckets[ idx]. end_value );
576
+ get_end_value ( idx) );
542
577
max= left_fract + sel * (buckets[idx].cum_fract - left_fract);
543
578
}
544
579
else
0 commit comments