List:Commits« Previous MessageNext Message »
From:Guilhem Bichot Date:February 3 2011 1:05pm
Subject:bzr commit into mysql-next-mr-bugfixing branch (guilhem.bichot:3245)
View as plain text  
#At file:///home/mysql_src/bzrrepos_new/mysql-next-mr-opt-backporting-wl4800-applying-Tor-s-review/ based on revid:guilhem.bichot@stripped

 3245 Guilhem Bichot	2011-02-03
      Applying review comments (more edits to come).

    modified:
      sql/opt_trace.cc
      sql/opt_trace.h
      sql/opt_trace2server.cc
      unittest/gunit/opt_trace-t.cc
=== modified file 'sql/opt_trace.cc'
--- a/sql/opt_trace.cc	2011-01-26 10:57:25 +0000
+++ b/sql/opt_trace.cc	2011-02-03 13:05:38 +0000
@@ -55,16 +55,18 @@ void Opt_trace_struct::syntax_error(cons
 }
 
 
+namespace {
 /** opening and closing symbols for arrays ([])and objects ({}) */
-static const char brackets[]= { '[', '{', ']', '}' };
-static inline char opening_bracket(bool requires_key)
+const char brackets[]= { '[', '{', ']', '}' };
+inline char opening_bracket(bool requires_key)
 {
   return brackets[requires_key];
 }
-static inline char closing_bracket(bool requires_key)
+inline char closing_bracket(bool requires_key)
 {
   return brackets[requires_key + 2];
 }
+} // namespace
 
 
 void Opt_trace_struct::do_construct(Opt_trace_stmt *stmt_arg,
@@ -188,6 +190,8 @@ void Opt_trace_struct::do_destruct()
    @note add() has an up-front if(), hopefully inlined, so that in the common
    case - tracing run-time disabled - we have no function call. If tracing is
    enabled, we call do_add().
+   In a 20-table plan search (as in BUG#50595), the execution time was
+   decreased from 2.6 to 2.0 seconds thanks to this inlined-if trick.
 */
 Opt_trace_struct& Opt_trace_struct::do_add(const char *key, const char *val,
                                            const size_t val_length,
@@ -243,11 +247,11 @@ Opt_trace_struct& Opt_trace_struct::do_a
       /*
         Such UTF8 can now be safely escaped. Because UTF8 has the same
         characters in range 0-127 as ASCII does, and other UTF8 characters
-        don't contain 0-127 bytes, if we see a 0 byte it is really the NUL
-        character and not a part of a longer character, if we see a newline,
-        same, etc. That wouldn't necessarily be true if we used
-        query_charset as target character set, so escaping would be
-        impossible.
+        don't contain 0-127 bytes, if we see a byte equal to 0 it is really
+        the UTF8 u0000 character (a.k.a. ASCII NUL) and not a part of a longer
+        character; if we see a newline, same, etc. That wouldn't necessarily
+        be true if we used query_charset as target character set, so escaping
+        would be impossible.
       */
       stmt->trace_buffer.append_escaped(utf8_str, new_length);
       my_free(utf8_str);
@@ -281,7 +285,7 @@ Opt_trace_struct& Opt_trace_struct::do_a
 Opt_trace_struct& Opt_trace_struct::do_add(const char *key, longlong val)
 {
   DBUG_ASSERT(started);
-  char buf[22];                                 // magic constant
+  char buf[22];                     // 22 is enough for digits of a 64-bit int
   llstr(val, buf);
   DBUG_PRINT("opt_trace", ("%s: %s", key, buf));
   if (!stmt->support_I_S)
@@ -311,7 +315,7 @@ Opt_trace_struct& Opt_trace_struct::do_a
 Opt_trace_struct& Opt_trace_struct::do_add(const char *key, double val)
 {
   DBUG_ASSERT(started);
-  char buf[32];                                 // magic constant
+  char buf[32];                         // 32 is enough for digits of a double
   my_snprintf(buf, sizeof(buf), "%g", val);
   DBUG_PRINT("opt_trace", ("%s: %s", key, buf));
   if (!stmt->support_I_S)
@@ -593,11 +597,10 @@ bool Opt_trace_context::start(bool suppo
     since_offset_0++;
   }
 
-  Opt_trace_stmt *stmt= new Opt_trace_stmt(this, current_stmt_in_gen,
-                                           new_stmt_support_I_S);
+  Opt_trace_stmt *stmt= new(std::nothrow)
+    Opt_trace_stmt(this, current_stmt_in_gen, new_stmt_support_I_S);
   DBUG_PRINT("opt_trace",("new stmt %p support_I_S %d", stmt,
                           (int)new_stmt_support_I_S));
-  // new cannot return NULL.
   if (stmt == NULL)
     DBUG_RETURN(true);
 
@@ -745,11 +748,11 @@ void Opt_trace_iterator::next()
 /**
    @note Because allocation is done in big chunks, buffer->Ptr[str_length]
    may be uninitialized while buffer->Ptr[allocated length] is 0, so we
-   must use c_ptr_safe() as we want a NUL-terminated string (which is easier
+   must use c_ptr_safe() as we want a 0-terminated string (which is easier
    to manipulate in a debugger, or to compare in unit tests with
    EXPECT_STREQ).
    c_ptr_safe() may realloc an empty String from 0 bytes to 8 bytes,
-   when it adds the closing NUL.
+   when it adds the closing \0.
 */
 Opt_trace_info Opt_trace_iterator::get_value()
 {
@@ -768,8 +771,6 @@ Opt_trace_info Opt_trace_iterator::get_v
 
 /* Opt_trace_stmt class */
 
-const size_t Opt_trace_stmt::empty_trace_len= 4; // magic number
-
 Opt_trace_stmt::Opt_trace_stmt(Opt_trace_context *ctx_arg,
                                Opt_trace_stmt *parent_arg,
                                bool support_I_S_arg):
@@ -789,11 +790,8 @@ void Opt_trace_stmt::end()
   DBUG_ASSERT(current_depth == 0);
   current_depth= 0;
   started= false;
-  /* Send the full nice trace to DBUG */
+  // Send the full nice trace to DBUG.
   DBUG_EXECUTE("opt_trace",
-               if (trace_buffer.length() <= empty_trace_len)
-               { /*  don't spam DBUG with empty trace */ }
-               else
                {
                  const char *trace= trace_buffer.c_ptr_safe();
                  DBUG_LOCK_FILE;
@@ -806,26 +804,28 @@ void Opt_trace_stmt::end()
 }
 
 
-static const char my_spaces[] =
-  "                                                                "
-  "                                                                "
-  "                                                                "
-  "                                                                "
+namespace {
+const char my_spaces[] =
   "                                                                "
   "                                                                "
   "                                                                "
-  ; // Extend as desired, to max supported indentation level.
+  ;
+}
+
 void Opt_trace_stmt::next_line()
 {
   if (ctx->one_line)
     return;
   trace_buffer.append('\n');
 
-  // You can get away with a single append here:
-  int ix= sizeof(my_spaces) - 2*current_depth - 1;
-  if (ix < 0)
-    ix= 0;
-  trace_buffer.append(&my_spaces[ix]);
+  int to_be_printed= 2 * current_depth;
+  const int spaces_len= sizeof(my_spaces) - 1;
+  while (to_be_printed > spaces_len)
+  {
+    trace_buffer.append(my_spaces);
+    to_be_printed-= spaces_len;
+  }
+  trace_buffer.append(my_spaces, to_be_printed);
 }
 
 
@@ -1020,9 +1020,13 @@ bool Opt_trace_stmt::Buffer::append_esca
           else
             *pbuf++= c; // Normal character, no escaping needed.
         }
-        if (pbuf > buf + (sizeof(buf) - 6))     // magic number
+        /*
+          To fit a next character, we need at most 6 bytes (happens when using
+          \uXXXX syntax) before the buffer's end:
+        */
+        if (pbuf > buf + (sizeof(buf) - 6))
         {
-          // No room in 'buf' for next char, so flush it.
+          // Possibly no room in 'buf' for next char, so flush buf.
           rc|= string_buf.append(buf, pbuf - buf);
           pbuf= buf; // back to buf's start
         }

=== modified file 'sql/opt_trace.h'
--- a/sql/opt_trace.h	2011-01-26 10:57:25 +0000
+++ b/sql/opt_trace.h	2011-02-03 13:05:38 +0000
@@ -673,9 +673,6 @@ private: // Except other classes in this
 
   Opt_trace_stmt *prev, *next; ///< list management
 
-  /** Length of an empty trace */
-  static const size_t empty_trace_len;
-
 public:
   const Opt_trace_stmt *prev_() const { return prev; }
 
@@ -698,12 +695,12 @@ public:
 struct Opt_trace_info
 {
   /**
-     String containing trace. It is NUL-terminated, only to aid debugging or
+     String containing trace. It is 0-terminated, only to aid debugging or
      unit testing; this property is not relied upon in normal server usage.
   */
   const char *trace_ptr;
   size_t trace_length;   ///< length of trace string
-  /** String containing query. NUL-termination: like trace_ptr */
+  /** String containing query. 0-termination: like trace_ptr */
   const char *query_ptr;
   size_t query_length;   ///< length of query string
   CHARSET_INFO *query_charset; ///< charset of query string
@@ -725,7 +722,6 @@ class Opt_trace_iterator
 {
 public:
   /**
-    Constructor.
     @param  ctx  context
     @note row_count starts at 1 because after construction we are
     positioned either:
@@ -1077,17 +1073,15 @@ private:
      Whether the structure requires/forbids keys for values inside it.
      1: this is an object. 0: this is an array. Other: incorrect.
 
-     it is unclear at this point why it is int8 rather than bool
-
-     @note The canonical way would be to not have such int8 per instance, but
+     @note The canonical way would be to not have such bool per instance, but
      rather have a pure virtual method Opt_trace_struct::requires_key(),
 C++ has member functions, not methods.
      overloaded by Opt_trace_object (returning 1) and by Opt_trace_array
      (returning 0). But Opt_trace_object::requires_key() would not be accessible
      from Opt_trace_struct::construct() (which would complicate coding), whereas
-     the int8 is.
+     the bool is.
   */
-  int8 requires_key;
+  bool requires_key;
   Opt_trace_stmt *stmt;  ///< Trace owning the structure
   /** Parent structure ("outer structure" of the structure) */
   Opt_trace_struct *parent;
@@ -1198,7 +1192,6 @@ class Opt_trace_disable_I_S
 {
 public:
   /**
-     Constructor
      @param  ctx_arg      Context.
      @param  disable_arg  Whether the instance should really disable
                           anything. If false, the object is dummy. If true,
@@ -1319,22 +1312,17 @@ void opt_trace_print_expanded_query(THD 
 */
 void opt_trace_add_select_number(Opt_trace_struct *s,
                                  uint select_number);
-
-
-  /**
-     Set the "original query" for the current statement.
-     @param   trace    trace context
-     @param   query    query
-     @param   length   query's length
-     @param   charset  charset which was used to encode this query
-     @retval  false    ok
-     @retval  true     error
-  */
-static inline bool opt_trace_set_query(Opt_trace_context *trace,
-                                       const char *query,
-                                       size_t query_length,
-                                       CHARSET_INFO *query_charset)
-{ return trace->set_query(query, query_length, query_charset); }
+/**
+   Set the "original query" for the current statement.
+   @param   trace    trace context
+   @param   query    query
+   @param   length   query's length
+   @param   charset  charset which was used to encode this query
+   @retval  false    ok
+   @retval  true     error
+*/
+bool opt_trace_set_query(Opt_trace_context *trace, const char *query,
+                         size_t query_length, CHARSET_INFO *query_charset);
 
 /**
    Fills information_schema.OPTIMIZER_TRACE with rows (one per trace)

=== modified file 'sql/opt_trace2server.cc'
--- a/sql/opt_trace2server.cc	2011-01-26 10:57:25 +0000
+++ b/sql/opt_trace2server.cc	2011-02-03 13:05:38 +0000
@@ -29,6 +29,10 @@
 
 #ifdef OPTIMIZER_TRACE
 
+namespace {
+
+const char I_S_table_name[]= "OPTIMIZER_TRACE";
+
 /* Standalone functions */
 
 /**
@@ -39,9 +43,8 @@
    OPTIMIZER_TRACE will overwrite OPTIMIZER_TRACE as it runs and provide
    uninteresting info.
 */
-static bool list_has_optimizer_trace_table(const TABLE_LIST *tbl)
+bool list_has_optimizer_trace_table(const TABLE_LIST *tbl)
 {
-  static const char I_S_table_name[]= "OPTIMIZER_TRACE";
   for( ; tbl ; tbl= tbl->next_global)
   {
     if (tbl->schema_table &&
@@ -56,8 +59,7 @@ static bool list_has_optimizer_trace_tab
    Whether a SQL command qualifies for optimizer tracing.
    @param  sql_command  the command
 */
-static inline bool
-sql_command_can_be_traced(enum enum_sql_command sql_command)
+inline bool sql_command_can_be_traced(enum enum_sql_command sql_command)
 {
   /*
     Tracing is limited to a few SQL commands only.
@@ -82,6 +84,7 @@ sql_command_can_be_traced(enum enum_sql_
   return (sql_command_flags[sql_command] & CF_OPTIMIZER_TRACE);
 }
 
+} // namespace
 
 bool opt_trace_start(THD *thd, const TABLE_LIST *tbl,
                      enum enum_sql_command sql_command)
@@ -118,8 +121,7 @@ bool opt_trace_start(THD *thd, const TAB
   */
   if (thd->opt_trace == NULL)
   {
-    // (this version of) operator new can never return NULL.
-    if ((thd->opt_trace= new Opt_trace_context) == NULL)
+    if ((thd->opt_trace= new(std::nothrow) Opt_trace_context) == NULL)
       goto disable;
     allocated_here= true;
   }
@@ -223,6 +225,13 @@ void opt_trace_add_select_number(Opt_tra
 }
 
 
+bool opt_trace_set_query(Opt_trace_context *trace, const char *query,
+                         size_t query_length, CHARSET_INFO *query_charset)
+{
+  return trace->set_query(query, query_length, query_charset);
+}
+
+
 int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *cond)
 {
 #ifdef OPTIMIZER_TRACE

=== modified file 'unittest/gunit/opt_trace-t.cc'
--- a/unittest/gunit/opt_trace-t.cc	2011-01-26 10:57:25 +0000
+++ b/unittest/gunit/opt_trace-t.cc	2011-02-03 13:05:38 +0000
@@ -88,7 +88,7 @@ TEST_F(TraceContentTest, ConstructAndDes
 
 
 /** Test empty trace */
-TEST_F(TraceContentTest, empty)
+TEST_F(TraceContentTest, Empty)
 {
   ASSERT_FALSE(trace.start(true, false, false, -1, 1, ULONG_MAX, all_features));
   /*
@@ -170,7 +170,7 @@ TEST_F(TraceContentTest, NormalUsage)
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   check_json_compliance(info.trace_ptr, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -181,7 +181,7 @@ TEST_F(TraceContentTest, NormalUsage)
    Test Opt_trace_context::get_tail(). Same as TraceContentTest.NormalUsage
    but with a get_tail() in the middle.
 */
-TEST_F(TraceContentTest, tail)
+TEST_F(TraceContentTest, Tail)
 {
   ASSERT_FALSE(trace.start(true, true, false, -1, 1, ULONG_MAX, all_features));
   {
@@ -230,8 +230,8 @@ TEST_F(TraceContentTest, tail)
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   EXPECT_EQ((void *)0, info.query_ptr);
-  EXPECT_EQ((size_t)0, info.query_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.query_length);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   EXPECT_EQ(0, strcmp(expected + sizeof(expected) - 1 - 40, tail));
   it.next();
@@ -287,7 +287,7 @@ TEST_F(TraceContentTest, BuggyObject)
     "}";
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -332,7 +332,7 @@ TEST_F(TraceContentTest, BuggyArray)
     "}";
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -398,15 +398,15 @@ TEST_F(TraceContentTest, DisableIS)
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   check_json_compliance(info.trace_ptr, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
 }
 
 /** Helper for Trace_settings_test.offset */
-static void make_one_trace(Opt_trace_context *trace, const char *name,
-                           long offset, long limit)
+void make_one_trace(Opt_trace_context *trace, const char *name,
+                    long offset, long limit)
 {
   ASSERT_FALSE(trace->start(true, true, false, offset, limit, ULONG_MAX,
                             all_features));
@@ -445,7 +445,7 @@ void do_check(Opt_trace_context *trace, 
     const size_t name_len= strlen(*name);
     EXPECT_EQ(name_len + 11, info.trace_length);
     EXPECT_EQ(0, strncmp(info.trace_ptr + 5, *name, name_len));
-    EXPECT_EQ((size_t)0, info.missing_bytes);
+    EXPECT_EQ(0U, info.missing_bytes);
     EXPECT_EQ(false, info.malloc_error);
     it.next();
   }
@@ -454,7 +454,7 @@ void do_check(Opt_trace_context *trace, 
 
 
 /** Test offset/limit variables */
-TEST(TraceSettingsTest, offset)
+TEST(TraceSettingsTest, Offset)
 {
   Opt_trace_context trace;
   make_one_trace(&trace, "100", -1 /* offset */, 1 /* limit */);
@@ -536,8 +536,8 @@ TEST(TraceSettingsTest, MaxMemSize)
     Without truncation the trace would take:
     2+17+3+1+20*100 = 2023
   */
-  EXPECT_EQ((size_t)996, info.trace_length);
-  EXPECT_EQ((size_t)1027, info.missing_bytes); // 996+1027=2023
+  EXPECT_EQ(996U, info.trace_length);
+  EXPECT_EQ(1027U, info.missing_bytes); // 996+1027=2023
   EXPECT_EQ(false, info.malloc_error);
   EXPECT_EQ(0, strncmp(expected, info.trace_ptr, sizeof(expected) - 1));
   it.next();
@@ -568,14 +568,14 @@ TEST(TraceSettingsTest, MaxMemSize2)
   Opt_trace_iterator it(&trace);
   ASSERT_FALSE(it.at_end());
   Opt_trace_info info= it.get_value();
-  EXPECT_EQ((size_t)17, info.trace_length);
-  EXPECT_EQ((size_t)16, info.missing_bytes);
+  EXPECT_EQ(17U, info.trace_length);
+  EXPECT_EQ(16U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   info= it.get_value();
   /* 2nd trace completely empty as first trace left no room */
-  EXPECT_EQ((size_t)0, info.trace_length);
-  EXPECT_EQ((size_t)33, info.missing_bytes);
+  EXPECT_EQ(0U, info.trace_length);
+  EXPECT_EQ(33U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -592,8 +592,8 @@ TEST(TraceSettingsTest, MaxMemSize2)
   Opt_trace_iterator it2(&trace);
   ASSERT_FALSE(it2.at_end());
   info= it2.get_value();
-  EXPECT_EQ((size_t)0, info.trace_length);
-  EXPECT_EQ((size_t)33, info.missing_bytes);
+  EXPECT_EQ(0U, info.trace_length);
+  EXPECT_EQ(33U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it2.next();
   info= it2.get_value();
@@ -601,8 +601,8 @@ TEST(TraceSettingsTest, MaxMemSize2)
     3rd one had room. A bit less than first, because just reading the second
     with the iterator has reallocated the second from 0 to 8 bytes...
   */
-  EXPECT_EQ((size_t)14, info.trace_length);
-  EXPECT_EQ((size_t)19, info.missing_bytes);
+  EXPECT_EQ(14U, info.trace_length);
+  EXPECT_EQ(19U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it2.next();
   ASSERT_TRUE(it2.at_end());
@@ -636,7 +636,7 @@ TEST_F(TraceContentTest, OutOfMemory)
     "}";
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(true, info.malloc_error);   // malloc error reported
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -698,7 +698,7 @@ TEST_F(TraceContentTest, FilteringByFeat
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   check_json_compliance(info.trace_ptr, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   it.next();
   ASSERT_TRUE(it.at_end());
@@ -706,7 +706,7 @@ TEST_F(TraceContentTest, FilteringByFeat
 
 
 /** Test escaping of characters */
-TEST_F(TraceContentTest, escaping)
+TEST_F(TraceContentTest, Escaping)
 {
   ASSERT_EQ(false, trace.start(true, true, false, -1, 1, ULONG_MAX,
                                all_features));
@@ -736,7 +736,7 @@ TEST_F(TraceContentTest, escaping)
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   check_json_compliance(info.trace_ptr, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   EXPECT_EQ(sizeof(all_chars), info.query_length);
   // we get the query unescaped, verbatim, not 0-terminated:
@@ -797,7 +797,7 @@ TEST_F(TraceContentTest, NonUtf8)
   EXPECT_STREQ(expected, info.trace_ptr);
   EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
   check_json_compliance(info.trace_ptr, info.trace_length);
-  EXPECT_EQ((size_t)0, info.missing_bytes);
+  EXPECT_EQ(0U, info.missing_bytes);
   EXPECT_EQ(false, info.malloc_error);
   EXPECT_EQ(sizeof(all_chars), info.query_length);
   // we get the query unescaped, verbatim, not 0-terminated:
@@ -806,6 +806,70 @@ TEST_F(TraceContentTest, NonUtf8)
   ASSERT_TRUE(it.at_end());
 }
 
+
+void open_object(Opt_trace_context *trace)
+{
+  static int count= 100;
+  if (count == 0)
+    return;
+  count--;
+  Opt_trace_object oto(trace, "abc");
+  open_object(trace);
+}
+
+/**
+   Test indentation by many blanks.
+   By creating a 100-level deep structure, we force an indentation which
+   enters the while() block in Opt_trace_stmt::next_line().
+*/
+TEST_F(TraceContentTest, Indent)
+{
+  ASSERT_EQ(false, trace.start(true, false, false, -1, 1, ULONG_MAX,
+                               all_features));
+  {
+    Opt_trace_object oto(&trace);
+    open_object(&trace);
+  }
+  trace.end();
+  Opt_trace_iterator it(&trace);
+  ASSERT_FALSE(it.at_end());
+  const Opt_trace_info info= it.get_value();
+  /*
+    Formula for the expected size.
+    Before the Nth call to open_object(), indentation inside the innermost
+    empty object is noted I(N); so the relationship between the size before
+    Nth call and the size after Nth call is:
+    S(N+1) = S(N)
+             + I(N)   (indentation before added '"abc": {\n' )
+             + 9      (length of added '"abc": {\n' )
+             + I(N)   (indentation before added '}\n' )
+             + 2      (length of added '}\n' )
+    and the indentation is increased by two as we are one level deeper:
+    I(N+1) = I(N) + 2
+    With S(1) = 3 (length of '{\n}') and I(1) = 2.
+    So I(N) = 2 * N and
+    S(N+1) - S(N) = 11 + 4 * N
+    So S(N) = 3 + 11 * (N - 1) + 2 * N * (N - 1).
+    For 100 calls, the final size is S(101) = 21303.
+    Each call adds 10 non-space characters, so there should be
+    21303
+    - 10 * 100 (added non-spaces characters)
+    - 3 (non-spaces of initial object before first function call)
+    = 20300 spaces.
+  */
+  EXPECT_EQ(21303U, info.trace_length);
+  uint spaces= 0;
+  for (uint i= 0; i < info.trace_length; i++)
+    if (info.trace_ptr[i] == ' ')
+      spaces++;
+  EXPECT_EQ(20300U, spaces);
+  check_json_compliance(info.trace_ptr, info.trace_length);
+  EXPECT_EQ(0U, info.missing_bytes);
+  EXPECT_EQ(false, info.malloc_error);
+  it.next();
+  ASSERT_TRUE(it.at_end());
+}
+
 }  // namespace
 
 #endif // OPTIMIZER_TRACE


Attachment: [text/bzr-bundle] bzr/guilhem.bichot@oracle.com-20110203130538-t3ciy5d90g5ae53m.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (guilhem.bichot:3245) Guilhem Bichot3 Feb