24 #include "sql_string.h"
27 #ifdef OPTIMIZER_TRACE
30 namespace random_name_to_avoid_gcc_bug_29365 {
39 size_t allowed_mem_size;
43 Buffer() : allowed_mem_size(0), missing_bytes(0) {}
45 uint32 alloced_length()
const {
return string_buf.alloced_length(); }
46 uint32 length()
const {
return string_buf.length(); }
48 char *c_ptr_safe() {
return string_buf.c_ptr_safe(); }
49 const char *ptr()
const {
return string_buf.ptr(); }
51 const CHARSET_INFO *charset()
const {
return string_buf.charset(); }
53 { string_buf.set_charset(charset); }
60 void append(
const char *str,
size_t length);
61 void append(
const char *str) {
return append(str, strlen(str)); }
68 void append_escaped(
const char *str,
size_t length);
69 void append(
char chr);
71 size_t get_allowed_mem_size()
const {
return allowed_mem_size; }
72 size_t get_missing_bytes()
const {
return missing_bytes; }
74 void set_allowed_mem_size(
size_t a) { allowed_mem_size= a; }
81 using random_name_to_avoid_gcc_bug_29365::Buffer;
108 bool has_ended()
const {
return ended; }
111 void set_allowed_mem_size(
size_t size);
114 void set_query(
const char*
query,
size_t length,
130 bool open_struct(
const char *key, Opt_trace_struct *ots,
131 bool wants_disable_I_S,
char opening_bracket);
141 void close_struct(
const char *saved_key,
bool has_disabled_I_S,
142 char closing_bracket);
161 void add(
const char *key,
const char *val,
size_t val_length,
162 bool quotes,
bool escape);
167 void fill_info(Opt_trace_info *info)
const;
170 const char *trace_buffer_tail(
size_t size);
173 size_t alloced_length()
const
174 {
return trace_buffer.alloced_length() + query_buffer.alloced_length(); }
176 void assert_current_struct(
const Opt_trace_struct *s)
const
177 { DBUG_ASSERT(current_struct == s); }
180 void missing_privilege();
182 bool support_I_S()
const {
return I_S_disabled == 0; }
185 void disable_I_S() { ++I_S_disabled; }
191 void restore_I_S() { --I_S_disabled; }
198 const char *make_unknown_key();
221 Opt_trace_struct *current_struct;
234 uint unknown_key_count;
236 char unknown_key[24];
244 const char brackets[]= {
'[',
'{',
']',
'}' };
245 inline char opening_bracket(
bool requires_key)
247 return brackets[requires_key];
249 inline char closing_bracket(
bool requires_key)
251 return brackets[requires_key + 2];
257 bool requires_key_arg,
262 requires_key= requires_key_arg;
264 DBUG_PRINT(
"opt", (
"%s: starting struct", key));
265 stmt= ctx->get_current_stmt_in_gen();
269 has_disabled_I_S= !ctx->feature_enabled(feature);
271 if (likely(!stmt->open_struct(key,
this, has_disabled_I_S,
272 opening_bracket(requires_key))))
277 void Opt_trace_struct::do_destruct()
279 DBUG_PRINT(
"opt", (
"%s: ending struct", saved_key));
280 DBUG_ASSERT(started);
281 stmt->close_struct(saved_key, has_disabled_I_S,
282 closing_bracket(requires_key));
294 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key,
const char *val,
298 DBUG_ASSERT(started);
299 DBUG_PRINT(
"opt", (
"%s: \"%.*s\"", key, (
int)val_length, val));
300 stmt->add(key, val, val_length,
true, escape);
306 LEX_CSTRING bool_as_text[]= { { STRING_WITH_LEN(
"false") },
307 { STRING_WITH_LEN(
"true") } };
310 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key,
bool val)
312 DBUG_ASSERT(started);
313 DBUG_PRINT(
"opt", (
"%s: %d", key, (
int)val));
315 stmt->add(key, text->str, text->length,
false,
false);
320 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key, longlong val)
322 DBUG_ASSERT(started);
325 DBUG_PRINT(
"opt", (
"%s: %s", key, buf));
326 stmt->add(key, buf, strlen(buf),
false,
false);
331 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key, ulonglong val)
333 DBUG_ASSERT(started);
336 DBUG_PRINT(
"opt", (
"%s: %s", key, buf));
337 stmt->add(key, buf, strlen(buf),
false,
false);
342 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key,
double val)
344 DBUG_ASSERT(started);
346 my_snprintf(buf,
sizeof(buf),
"%g", val);
347 DBUG_PRINT(
"opt", (
"%s: %s", key, buf));
348 stmt->add(key, buf, strlen(buf),
false,
false);
353 Opt_trace_struct& Opt_trace_struct::do_add_null(
const char *key)
355 DBUG_ASSERT(started);
356 DBUG_PRINT(
"opt", (
"%s: null", key));
357 stmt->add(key, STRING_WITH_LEN(
"null"),
false,
false);
362 Opt_trace_struct& Opt_trace_struct::do_add(
const char *key,
Item *item)
365 String str(buff,(uint32)
sizeof(buff), system_charset_info);
370 item->
print(&str, enum_query_type(QT_TO_SYSTEM_CHARSET |
371 QT_SHOW_SELECT_NUMBER |
374 return do_add(key, str.ptr(), str.length(),
true);
377 return do_add_null(key);
381 Opt_trace_struct& Opt_trace_struct::do_add_hex(
const char *key, uint64 val)
383 DBUG_ASSERT(started);
384 char buf[2 + 16], *p_end= buf +
sizeof(
buf) - 1, *p= p_end;
387 *p--= _dig_vec_lower[val & 15];
388 *p--= _dig_vec_lower[(val & 240) >> 4];
395 const int len= p_end + 1 - p;
396 DBUG_PRINT(
"opt", (
"%s: %.*s", key, len, p));
397 stmt->add(check_key(key), p, len,
false,
false);
402 Opt_trace_struct& Opt_trace_struct::do_add_utf8_table(
const TABLE *tab)
404 TABLE_LIST *
const tl= tab->pos_in_table_list;
408 tl->
print(tab->in_use, &str, enum_query_type(QT_TO_SYSTEM_CHARSET |
409 QT_SHOW_SELECT_NUMBER |
411 QT_DERIVED_TABLE_ONLY_ALIAS));
412 return do_add(
"table", str.ptr(), str.length(),
true);
418 const char *Opt_trace_struct::check_key(
const char *key)
420 DBUG_ASSERT(started);
422 stmt->assert_current_struct(
this);
423 bool has_key= key != NULL;
424 if (unlikely(has_key != requires_key))
427 key= has_key ? NULL : stmt->make_unknown_key();
437 DBUG_ASSERT(strncmp(previous_key, key,
sizeof(previous_key) - 1) != 0);
438 strncpy(previous_key, key,
sizeof(previous_key) - 1);
439 previous_key[
sizeof(previous_key) - 1]= 0;
449 ended(false), I_S_disabled(0), missing_priv(false), ctx(ctx_arg),
450 current_struct(NULL), unknown_key_count(0)
453 trace_buffer.set_charset(system_charset_info);
454 DBUG_ASSERT(system_charset_info == &my_charset_utf8_general_ci);
458 void Opt_trace_stmt::end()
460 DBUG_ASSERT(stack_of_current_structs.elements() == 0);
461 DBUG_ASSERT(I_S_disabled >= 0);
472 trace_buffer.c_ptr_safe();
476 const char *trace= trace_buffer.c_ptr_safe();
478 fputs(
"Complete optimizer trace:", DBUG_FILE);
479 fputs(trace, DBUG_FILE);
480 fputs(
"\n", DBUG_FILE);
484 if (unlikely(missing_priv))
489 void Opt_trace_stmt::set_allowed_mem_size(
size_t size)
491 trace_buffer.set_allowed_mem_size(size);
495 void Opt_trace_stmt::set_query(
const char *
query,
size_t length,
499 DBUG_ASSERT(query_buffer.ptr() == NULL);
500 query_buffer.set_charset(charset);
511 (trace_buffer.alloced_length() >= trace_buffer.get_allowed_mem_size()) ?
512 0 : (trace_buffer.get_allowed_mem_size() - trace_buffer.alloced_length());
513 query_buffer.set_allowed_mem_size(available);
515 query_buffer.append(query, length);
517 const size_t new_allowed_mem_size=
518 (query_buffer.alloced_length() >= trace_buffer.get_allowed_mem_size()) ?
519 0 : (trace_buffer.get_allowed_mem_size() - query_buffer.alloced_length());
520 trace_buffer.set_allowed_mem_size(new_allowed_mem_size);
524 bool Opt_trace_stmt::open_struct(
const char *key, Opt_trace_struct *ots,
525 bool wants_disable_I_S,
526 char opening_bracket)
530 if (wants_disable_I_S)
542 if (current_struct != NULL)
545 current_struct->add_alnum(key,
"...");
547 current_struct->add_alnum(
"...");
552 trace_buffer.prealloc();
553 add(key, &opening_bracket, 1,
false,
false);
556 if (wants_disable_I_S)
557 ctx->disable_I_S_for_this_and_children();
559 DBUG_EXECUTE_IF(
"opt_trace_oom_in_open_struct",
560 DBUG_SET(
"+d,simulate_out_of_memory"););
561 const bool rc= stack_of_current_structs.append(current_struct);
567 DBUG_EXECUTE_IF(
"opt_trace_oom_in_open_struct",
568 DBUG_SET(
"-d,simulate_out_of_memory"););
577 void Opt_trace_stmt::close_struct(
const char *saved_key,
578 bool has_disabled_I_S,
579 char closing_bracket)
585 current_struct= *(stack_of_current_structs.back());
586 stack_of_current_structs.pop();
590 trace_buffer.append(closing_bracket);
591 if (ctx->get_end_marker() && saved_key != NULL)
593 trace_buffer.append(STRING_WITH_LEN(
" /* "));
594 trace_buffer.append(saved_key);
595 trace_buffer.append(STRING_WITH_LEN(
" */"));
598 if (has_disabled_I_S)
603 void Opt_trace_stmt::separator()
605 DBUG_ASSERT(support_I_S());
607 if (current_struct != NULL)
609 if (!current_struct->set_not_empty())
610 trace_buffer.append(
',');
617 const char my_spaces[] =
625 void Opt_trace_stmt::next_line()
627 if (ctx->get_one_line())
629 trace_buffer.append(
'\n');
631 uint to_be_printed= 2 * stack_of_current_structs.elements();
632 const size_t spaces_len=
sizeof(my_spaces) - 1;
633 while (to_be_printed > spaces_len)
635 trace_buffer.append(my_spaces, spaces_len);
636 to_be_printed-= spaces_len;
638 trace_buffer.append(my_spaces, to_be_printed);
642 const char *Opt_trace_stmt::make_unknown_key()
644 my_snprintf(unknown_key,
sizeof(unknown_key),
645 "unknown_key_%u", ++unknown_key_count);
650 void Opt_trace_stmt::add(
const char *key,
const char *val,
size_t val_length,
651 bool quotes,
bool escape)
656 if (current_struct != NULL)
657 key= current_struct->check_key(key);
660 trace_buffer.append(
'"');
661 trace_buffer.append(key);
662 trace_buffer.append(STRING_WITH_LEN(
"\": "));
665 trace_buffer.append(
'"');
672 trace_buffer.append_escaped(val, val_length);
674 trace_buffer.append(val, val_length);
676 trace_buffer.append(
'"');
680 void Opt_trace_stmt::fill_info(Opt_trace_info *info)
const
682 if (unlikely(info->missing_priv= missing_priv))
684 info->trace_ptr= info->query_ptr=
"";
685 info->trace_length= info->query_length= 0;
686 info->query_charset= &my_charset_bin;
687 info->missing_bytes= 0;
691 info->trace_ptr= trace_buffer.ptr();
692 info->trace_length= trace_buffer.length();
693 info->query_ptr= query_buffer.ptr();
694 info->query_length= query_buffer.length();
695 info->query_charset= query_buffer.charset();
696 info->missing_bytes= trace_buffer.get_missing_bytes() +
697 query_buffer.get_missing_bytes();
702 const char *Opt_trace_stmt::trace_buffer_tail(
size_t size)
704 size_t buffer_len= trace_buffer.length();
705 const char *ptr= trace_buffer.c_ptr_safe();
706 if (buffer_len > size)
707 ptr+= buffer_len -
size;
712 void Opt_trace_stmt::missing_privilege()
716 DBUG_PRINT(
"opt", (
"trace denied"));
720 ctx->disable_I_S_for_this_and_children();
727 namespace random_name_to_avoid_gcc_bug_29365 {
729 void Buffer::append_escaped(
const char *str,
size_t length)
731 if (alloced_length() >= allowed_mem_size)
733 missing_bytes+= length;
736 const char *pstr, *pstr_end;
739 for (pstr= str, pstr_end= (str + length) ; pstr < pstr_end ; pstr++)
762 case '\\': esc=
'\\';
break;
763 case '"' : esc=
'\"';
break;
764 case '\n': esc=
'n' ;
break;
765 case '\r': esc=
'r' ;
break;
766 case '\t': esc=
't' ;
break;
767 default : esc= 0 ;
break;
776 uint ascii_code= (uint)c;
792 *pbuf++= _dig_vec_lower[ascii_code];
801 if (pbuf > buf + (
sizeof(buf) - 6))
804 string_buf.append(buf, static_cast<uint32>(pbuf - buf));
809 string_buf.append(buf, static_cast<uint32>(pbuf - buf));
813 void Buffer::append(
const char *str,
size_t length)
815 if (alloced_length() >= allowed_mem_size)
817 missing_bytes+= length;
820 DBUG_EXECUTE_IF(
"opt_trace_oom_in_buffers",
821 DBUG_SET(
"+d,simulate_out_of_memory"););
822 string_buf.append(str, static_cast<uint32>(length));
823 DBUG_EXECUTE_IF(
"opt_trace_oom_in_buffers",
824 DBUG_SET(
"-d,simulate_out_of_memory"););
828 void Buffer::append(
char chr)
830 if (alloced_length() >= allowed_mem_size)
836 string_buf.append(chr);
840 void Buffer::prealloc()
842 const size_t alloced= alloced_length();
843 const size_t first_increment= 1024;
844 if ((alloced - length()) < (first_increment / 3))
860 size_t new_size= (alloced == 0) ? first_increment : (alloced * 15 / 10);
861 size_t max_size= allowed_mem_size;
871 const size_t safety_margin= ALIGN_SIZE(1) + 1 ;
872 if (max_size >= safety_margin)
874 max_size-= safety_margin;
875 if (new_size > max_size)
877 if (new_size >= alloced)
878 string_buf.realloc(static_cast<uint32>(new_size));
888 const char *Opt_trace_context::flag_names[]=
890 "enabled",
"one_line",
"default", NullS
893 const char *Opt_trace_context::feature_names[]=
895 "greedy_search",
"range_optimizer",
"dynamic_range",
896 "repeated_subselect",
"default", NullS
900 Opt_trace_context::default_features=
902 Opt_trace_context::RANGE_OPTIMIZER |
903 Opt_trace_context::DYNAMIC_RANGE |
904 Opt_trace_context::REPEATED_SUBSELECT);
907 Opt_trace_context::~Opt_trace_context()
909 if (unlikely(pimpl != NULL))
914 DBUG_ASSERT(pimpl->all_stmts_for_I_S.elements() == 0);
916 DBUG_ASSERT(pimpl->all_stmts_to_del.elements() == 0);
922 template<
class T> T * new_nothrow_w_my_error()
924 T *
const t=
new (std::nothrow) T();
925 if (unlikely(t == NULL))
926 my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR),
927 static_cast<int>(
sizeof(T)));
930 template<
class T,
class Arg> T * new_nothrow_w_my_error(Arg a)
932 T *
const t=
new (std::nothrow) T(a);
933 if (unlikely(t == NULL))
934 my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR),
935 static_cast<int>(
sizeof(T)));
940 bool Opt_trace_context::start(
bool support_I_S_arg,
941 bool support_dbug_or_missing_priv,
942 bool end_marker_arg,
bool one_line_arg,
943 long offset_arg,
long limit_arg,
944 ulong max_mem_size_arg, ulonglong features_arg)
946 DBUG_ENTER(
"Opt_trace_context::start");
948 if (I_S_disabled != 0)
950 DBUG_PRINT(
"opt", (
"opt_trace is already disabled"));
951 support_I_S_arg=
false;
960 if (!support_I_S_arg && !support_dbug_or_missing_priv)
963 if (likely(pimpl == NULL) || pimpl->current_stmt_in_gen == NULL)
987 DBUG_EXECUTE_IF(
"no_new_opt_trace_stmt", DBUG_ASSERT(0););
990 ((pimpl= new_nothrow_w_my_error<Opt_trace_context_impl>()) == NULL))
997 if (I_S_disabled == 0)
1005 pimpl->end_marker= end_marker_arg;
1006 pimpl->one_line= one_line_arg;
1007 pimpl->offset= offset_arg;
1008 pimpl->limit= limit_arg;
1009 pimpl->max_mem_size= max_mem_size_arg;
1012 Opt_trace_context::MISC);
1014 if (support_I_S_arg && pimpl->offset >= 0)
1017 if (pimpl->since_offset_0 < pimpl->offset)
1019 DBUG_PRINT(
"opt", (
"disabled: since_offset_0(%ld) < offset(%ld)",
1020 pimpl->since_offset_0, pimpl->offset));
1021 support_I_S_arg=
false;
1023 else if (pimpl->since_offset_0 >= (pimpl->offset + pimpl->limit))
1025 DBUG_PRINT(
"opt", (
"disabled: since_offset_0(%ld) >="
1026 " offset(%ld) + limit(%ld)",
1027 pimpl->since_offset_0, pimpl->offset, pimpl->limit));
1028 support_I_S_arg=
false;
1030 pimpl->since_offset_0++;
1037 Opt_trace_stmt *stmt= new_nothrow_w_my_error<Opt_trace_stmt>(
this);
1039 DBUG_PRINT(
"opt",(
"new stmt %p support_I_S %d", stmt, support_I_S_arg));
1041 if (unlikely(stmt == NULL ||
1042 pimpl->stack_of_current_stmts
1043 .append(pimpl->current_stmt_in_gen)))
1053 if (support_I_S_arg)
1054 list= &pimpl->all_stmts_for_I_S;
1057 stmt->disable_I_S();
1058 list= &pimpl->all_stmts_to_del;
1061 if (unlikely(list->
append(stmt)))
1064 pimpl->current_stmt_in_gen= stmt;
1069 stmt->set_allowed_mem_size(allowed_mem_size_for_current_stmt());
1079 void Opt_trace_context::end()
1081 DBUG_ASSERT(I_S_disabled >= 0);
1082 if (likely(pimpl == NULL))
1084 if (pimpl->current_stmt_in_gen != NULL)
1086 pimpl->current_stmt_in_gen->end();
1091 Opt_trace_stmt *
const parent= *(pimpl->stack_of_current_stmts.back());
1092 pimpl->stack_of_current_stmts.pop();
1093 pimpl->current_stmt_in_gen= parent;
1100 parent->set_allowed_mem_size(allowed_mem_size_for_current_stmt());
1123 DBUG_ASSERT(pimpl->stack_of_current_stmts.elements() == 0);
1127 bool Opt_trace_context::support_I_S()
const
1129 return (pimpl != NULL) && (pimpl->current_stmt_in_gen != NULL) &&
1130 pimpl->current_stmt_in_gen->support_I_S();
1134 void Opt_trace_context::purge_stmts(
bool purge_all)
1136 DBUG_ENTER(
"Opt_trace_context::purge_stmts");
1137 if (!purge_all && pimpl->offset >= 0)
1151 for (idx= (pimpl->all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
1154 ((pimpl->all_stmts_for_I_S.elements() + pimpl->offset) <= idx))
1164 DBUG_EXECUTE_IF(
"opt_trace_oom_in_purge",
1165 DBUG_SET(
"+d,simulate_out_of_memory"););
1166 if (likely(!pimpl->all_stmts_to_del
1167 .append(pimpl->all_stmts_for_I_S.at(idx))))
1168 pimpl->all_stmts_for_I_S.del(idx);
1177 DBUG_EXECUTE_IF(
"opt_trace_oom_in_purge",
1178 DBUG_SET(
"-d,simulate_out_of_memory"););
1182 for (idx= (pimpl->all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
1184 Opt_trace_stmt *stmt= pimpl->all_stmts_to_del.at(idx);
1186 bool skip_del=
false;
1187 DBUG_EXECUTE_IF(
"opt_trace_oom_in_purge", skip_del=
true;);
1189 const bool skip_del=
false;
1191 if (!stmt->has_ended() || skip_del)
1219 pimpl->all_stmts_to_del.del(idx);
1227 size_t Opt_trace_context::allowed_mem_size_for_current_stmt()
const
1231 for (idx= (pimpl->all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
1233 const Opt_trace_stmt *stmt= pimpl->all_stmts_for_I_S.at(idx);
1234 mem_size+= stmt->alloced_length();
1237 for (idx= (pimpl->all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
1239 const Opt_trace_stmt *stmt= pimpl->all_stmts_to_del.at(idx);
1240 mem_size+= stmt->alloced_length();
1243 mem_size-= pimpl->current_stmt_in_gen->alloced_length();
1244 size_t rc= (mem_size <= pimpl->max_mem_size) ?
1245 (pimpl->max_mem_size - mem_size) : 0;
1246 DBUG_PRINT(
"opt", (
"rc %llu max_mem_size %llu",
1247 (ulonglong)rc, (ulonglong)pimpl->max_mem_size));
1252 void Opt_trace_context::set_query(
const char *query,
size_t length,
1255 pimpl->current_stmt_in_gen->set_query(query, length, charset);
1259 void Opt_trace_context::reset()
1264 pimpl->since_offset_0= 0;
1268 void Opt_trace_context::
1269 Opt_trace_context_impl::disable_I_S_for_this_and_children()
1271 if (current_stmt_in_gen != NULL)
1272 current_stmt_in_gen->disable_I_S();
1276 void Opt_trace_context::Opt_trace_context_impl::restore_I_S()
1278 if (current_stmt_in_gen != NULL)
1279 current_stmt_in_gen->restore_I_S();
1283 void Opt_trace_context::missing_privilege()
1297 pimpl->current_stmt_in_gen->missing_privilege();
1301 const Opt_trace_stmt
1302 *Opt_trace_context::get_next_stmt_for_I_S(
long *got_so_far)
const
1304 const Opt_trace_stmt *p;
1305 if ((pimpl == NULL) ||
1306 (*got_so_far >= pimpl->limit) ||
1307 (*got_so_far >= pimpl->all_stmts_for_I_S.elements()))
1311 p= pimpl->all_stmts_for_I_S.at(*got_so_far);
1312 DBUG_ASSERT(p != NULL);
1322 ctx(ctx_arg), row_count(0)
1327 void Opt_trace_iterator::next()
1329 cursor= ctx->get_next_stmt_for_I_S(&row_count);
1333 void Opt_trace_iterator::get_value(Opt_trace_info *info)
const
1338 #endif // OPTIMIZER_TRACE