YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
bool json_unescape_to_string(constchar *val, int val_len, String* out)
{ // Make sure 'out' has some memory allocated. if (!out->alloced_length() && out->alloc(128)) returntrue;
while (1)
{
uchar *buf= (uchar*)out->ptr();
out->length(out->alloced_length());
int res= json_unescape(&my_charset_utf8mb4_bin,
(const uchar*)val,
(const uchar*)val + val_len,
out->charset(),
buf, buf + out->length()); if (res >= 0)
{
out->length(res); returnfalse; // Ok
} if (res == JSON_ERROR_ILLEGAL_SYMBOL) returntrue; // Invalid character
// We get here if the unescaped string didn't fit into memory. if (res == JSON_ERROR_OUT_OF_SPACE)
{ if (out->alloc(out->alloced_length()*2)) returntrue;
} else returntrue; // unknown error
}
}
class Histogram_json_builder : public Histogram_builder
{
Histogram_json_hb *histogram; /* Number of buckets in the histogram */
uint hist_width;
// If the bucket was empty, it would have been case #1.
DBUG_ASSERT(!bucket_is_empty());
/* Finalizethecurrentbucket.Putthereenoughvaluestomakeithold bucket_capacityvalues.
*/
append_to_bucket(bucket_capacity - bucket.size); if (records == count && !overflow)
{ if (finalize_bucket_with_end_value(elem)) return1;
} else
finalize_bucket();
if (overflow > 0)
{ // Then, start the new bucket with the remaining values. if (start_bucket(elem, overflow)) return1;
}
} else
{ // Case #3: there's not enough values to fill the current bucket. if (bucket_is_empty())
{ if (start_bucket(elem, elem_cnt)) return1;
} else
append_to_bucket(elem_cnt);
}
if (records == count)
{ // This is the final value group. if (!bucket_is_empty())
{ if (finalize_bucket_with_end_value(elem)) return1;
}
} return0;
}
Json_string size_str("size"); if (json_key_matches(je, size_str.get()))
{ if (json_read_value(je)) return1;
constchar *size= (constchar*)je->value_begin; char *size_end= (char*)je->value_end; int conv_err;
size_d= my_strtod(size, &size_end, &conv_err); if (conv_err)
{
*err= ".size member must be a floating-point value"; return1;
}
have_size= true; continue;
}
save1.restore_to(je);
Json_string ndv_str("ndv"); if (json_key_matches(je, ndv_str.get()))
{ if (json_read_value(je)) return1;
constchar *ndv= (constchar*)je->value_begin; char *ndv_end= (char*)je->value_end; int conv_err;
ndv_ll= my_strtoll10(ndv, &ndv_end, &conv_err); if (conv_err)
{
*err= ".ndv member must be an integer value"; return1;
}
have_ndv= true; continue;
}
save1.restore_to(je);
Json_string end_str("end"); if (json_key_matches(je, end_str.get()))
{ if (read_bucket_endpoint(je, field, &value_buf, err)) return1;
last_bucket_end_endp.assign(value_buf.ptr(), value_buf.length());
*assigned_last_end= true; continue;
}
save1.restore_to(je);
// Less common endpoints:
Json_string start_hex_str("start_hex"); if (json_key_matches(je, start_hex_str.get()))
{ if (read_hex_bucket_endpoint(je, field, &value_buf, err)) return1;
Json_string end_hex_str("end_hex"); if (json_key_matches(je, end_hex_str.get()))
{ if (read_hex_bucket_endpoint(je, field, &value_buf, err)) return1;
last_bucket_end_endp.assign(value_buf.ptr(), value_buf.length());
*assigned_last_end= true; continue;
}
save1.restore_to(je);
// Some unknown member. Skip it. if (json_skip_key(je)) return1;
}
if (rc) return1;
if (!have_start)
{
*err= "\"start\" element not present"; return1;
} if (!have_size)
{
*err= "\"size\" element not present"; return1;
} if (!have_ndv)
{
*err= "\"ndv\" element not present"; return1;
}
if (je.state != JST_OBJ_START)
{
err= "Root JSON element must be a JSON object"; goto err;
}
while (1)
{ if (json_scan_next(&je)) goto err; if (je.state == JST_OBJ_END) break; // End of object
if (je.state != JST_KEY) goto err; // Can' really have this: JSON object has keys in it
Json_string hist_key_name(JSON_NAME); if (json_key_matches(&je, hist_key_name.get()))
{
total_size= 0.0;
end_element= -1; if (json_scan_next(&je)) goto err;
if (je.state != JST_ARRAY_START)
{
err= "histogram_hb must contain an array"; goto err;
}
while (!(rc= parse_bucket(&je, field, &total_size, &end_assigned, &err)))
{ if (end_assigned && end_element != -1)
end_element= (int)buckets.size();
} if (rc > 0) // Got error other than EOF goto err;
} else
{ // Some unknown member. Skip it. if (json_skip_key(&je))
{ return1;
}
}
}
if (buckets.size() < 1)
{
err= "Histogram must have at least one bucket"; goto err;
}
if (end_element == -1)
{
buckets.back().start_value= last_bucket_end_endp;
} elseif (end_element < (int)buckets.size())
{
err= ".end is only allowed in the last bucket"; goto err;
}
// If the value is outside of the histogram's range, this will "clip" it to // first or last bucket. int endp_cmp; int idx= find_bucket(field, key, &endp_cmp);
// Find the leftmost bucket that contains the lookup value. // (If the lookup value is to the left of all buckets, find bucket #0) int endp_cmp; int idx= find_bucket(field, min_key, &endp_cmp);
double sel; // Special handling for buckets with ndv=1: if (buckets[idx].ndv == 1)
{ if (endp_cmp < 0)
sel= 0.0; elseif (endp_cmp > 0)
sel= 1.0; else// endp_cmp == 0.0
sel= (exclusive_endp)? 1.0 : 0.0;
} else
{
sel= position_in_interval(field, min_key, min_key_len,
buckets[idx].start_value,
get_end_value(idx));
} double left_fract= get_left_fract(idx);
min= left_fract + sel * (buckets[idx].cum_fract - left_fract);
} else
min= 0.0;
if (max_endp)
{ // The right endpoint cannot be NULL
DBUG_ASSERT(!(field->real_maybe_null() && max_endp->key[0])); bool inclusive_endp= (max_endp->flag == HA_READ_AFTER_KEY)? true: false; const uchar *max_key= max_endp->key;
uint max_key_len= max_endp->length; if (field->real_maybe_null())
{
max_key++;
max_key_len--;
} int endp_cmp; int idx= find_bucket(field, max_key, &endp_cmp);
if ((endp_cmp == 0) && !inclusive_endp)
{ /* Therangeis"col<$CONST"andwe'vefoundabucketstartingwith $CONST.
*/ if (idx > 0)
{ // Move to the previous bucket
endp_cmp= 1;
idx--;
} else
endp_cmp= -1;
} double sel;
// Special handling for buckets with ndv=1: if (buckets[idx].ndv == 1)
{ if (endp_cmp < 0)
sel= 0.0; elseif (endp_cmp > 0)
sel= 1.0; else// endp_cmp == 0.0
sel= inclusive_endp? 1.0 : 0.0;
} else
{
sel= position_in_interval(field, max_key, max_key_len,
buckets[idx].start_value,
get_end_value(idx));
} double left_fract= get_left_fract(idx);
max= left_fract + sel * (buckets[idx].cum_fract - left_fract);
} else
max= 1.0;
if (min > max)
{ /* Thiscanhappenduetoroundingerrors.
Whatistheacceptableerrorsize?Json_writer::add_double()uses %.11lgformat.Thisgives9digitsafterthedot.Ahistogrammayhave hundredsofbuckets,let'smultiplytheerrorby1000.9-3=6
*/
DBUG_ASSERT(max < min + 1e-6);
max= min;
} return max - min;
}
int Histogram_json_hb::find_bucket(const Field *field, const uchar *lookup_val, int *cmp)
{ int res; int low= 0; int high= (int)buckets.size() - 1;
*cmp= 1; // By default, (bucket[retval].start_value < *lookup_val)
Besidesthat,therearetwospecialcases:low=0andhigh=last_bucket. Handlethembelow.
*/ if (low == 0)
{
res= field->key_cmp(lookup_val, (uchar*)buckets[0].start_value.data()); if (res <= 0)
*cmp= res; else// res>0, lookup_val > buckets[0].start_value
{
res= field->key_cmp(lookup_val, (uchar*)buckets[high].start_value.data()); if (res >= 0) // lookup_val >= buckets[high].start_value
{ // Move to that bucket
low= high;
*cmp= res;
} else
*cmp= 1;
}
} elseif (high == (int)buckets.size() - 1)
{
res= field->key_cmp(lookup_val, (uchar*)buckets[high].start_value.data()); if (res >= 0)
{ // Ok the value is in the last bucket.
*cmp= res;
low= high;
} else
{ // The value is in the 'low' bucket.
res= field->key_cmp(lookup_val, (uchar*)buckets[low].start_value.data());
*cmp= res;
}
}
end: // Verification: *cmp has correct value
DBUG_ASSERT(SGN(*cmp) ==
SGN(field->key_cmp(lookup_val,
(uchar*)buckets[low].start_value.data()))); // buckets[low] <= lookup_val, with one exception of the first bucket.
DBUG_ASSERT(low == 0 ||
field->key_cmp((uchar*)buckets[low].start_value.data(), lookup_val)<= 0); // buckets[low+1] > lookup_val, with one exception of the last bucket
DBUG_ASSERT(low == (int)buckets.size()-1 ||
field->key_cmp((uchar*)buckets[low+1].start_value.data(), lookup_val)> 0); return low;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.8 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.