List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:December 21 2010 7:34am
Subject:bzr push into mysql-next-mr-bugfixing branch (jorgen.loland:3234 to 3242)
WL#4800
View as plain text  
 3242 Jorgen Loland	2010-12-21
      WL#4800: 
      
      Revert print_quick() and friends to how they are in 
      next-mr-opt-backporting, i.e., remove optimizer tracing from 
      this function since tracing of quick is performed in 
      TABLE_READ_PLAN::trace_basic_info() instead.
     @ WL4800_TODO.txt
        Update todo-list
     @ sql/opt_range.cc
        Revert print_quick() and friends to how they are in next-mr-opt-backporting.

    modified:
      WL4800_TODO.txt
      sql/opt_range.cc
 3241 Guilhem Bichot	2010-12-19 [merge]
      merge Jorgen's changes

    modified:
      WL4800_TODO.txt
 3240 Guilhem Bichot	2010-12-19
      applying review comments. Fix for build failures.

    modified:
      WL4800_TODO.txt
      mysql-test/r/mysqld--help-notwin.result
      mysql-test/r/optimizer_trace2.result
      mysql-test/t/optimizer_trace2.test
      sql/opt_range.cc
      sql/opt_trace.h
      sql/opt_trace2server.cc
      sql/sql_parse.cc
      sql/sql_prepare.cc
 3239 Guilhem Bichot	2010-12-03
      review comments. Fix for a bug with views (testcase will come later,
      part of bigger unfinished work).

    modified:
      sql/opt_trace.h
      sql/sql_view.cc
 3238 Guilhem Bichot	2010-11-26
      making use of sql_command_flags as advised by Davi

    modified:
      sql/opt_trace2server.cc
      sql/sql_class.h
      sql/sql_parse.cc
 3237 Guilhem Bichot	2010-11-26
      Limit optimizer tracing to a certain set of SQL commands (safer).
      All other changes in this patch follow from this goal.
     @ mysql-test/include/optimizer_trace.inc
        * Marks in queries (as /**/ comments )to facilitate understanding results
        (exactly identical queries make it hard).
        * Comments explaining why results now differ between non-ps and --ps-protocol:
        now in ps-protocol, PREPARE and EXECUTE both generate one trace. This wasn't
        the case before: this is because PREPARE and EXECUTE, in mysqltest, are
        sent via COM_STMT_(PREPARE|EXECUTE), which are handled in dispatch_command():
        ** COM_STMT_PREPARE never goes through mysql_execute_command() so the
        preparation was not traced (now that we trace in check_prepared_statement(),
        it is traced)
        ** COM_STMT_EXECUTE executes the prepared command with mysql_execute_command()
        so the execution was traced and is still traced.
     @ mysql-test/r/optimizer_trace_no_prot.result
        SET is not traced anymore. PREPARE CALL neither (thus we see the trace
        of the statement before PREPARE CALL, which is a SELECT).
     @ mysql-test/r/optimizer_trace_ps_prot.result
        Now that PREPARE SELECT and EXECUTE SELECT
     @ mysql-test/t/optimizer_trace2.test
        Now that CALL is not traced anymore, the testcase needs to use
        a top-statement which is traced (SELECT STORED_FUNC() instead of CALL),
        in order to keep the test's intention.
     @ sql/opt_trace.h
        Updating comments: EXECUTE is not traced anymore, it's the executed statement
        which is (one level below, in terms of stack frames...).
     @ sql/opt_trace2server.cc
        - let opt_trace_start() limit tracing to certain SQL commands
        - it sounds like the similar check done in opt_trace_print_expanded_query()
        would become unnecessary, but alas no, because sometimes we open tables
        before executing the command (see comments).
     @ sql/sql_parse.cc
        The check on CF_DIAGNOSTIC_STMT is not needed, as opt_trace_start()
        now checks sql_command.
     @ sql/sql_prepare.cc
        To have "PREPARE <command>" be traced only if <command> is in a certain set,
        we need to know <command>, which is possible only in check_prepared_statement();
        so we:
        - don't turn tracing on in mysql_execute_command() when command is SQLCOM_PREPARE
        (too early, not enough info)
        - check the _to-be-prepared_ command in check_prepared_statement() and decide then.

    modified:
      mysql-test/include/optimizer_trace.inc
      mysql-test/r/optimizer_trace2.result
      mysql-test/r/optimizer_trace_no_prot.result
      mysql-test/r/optimizer_trace_ps_prot.result
      mysql-test/t/optimizer_trace2.test
      sql/opt_trace.h
      sql/opt_trace2server.cc
      sql/sql_parse.cc
      sql/sql_prepare.cc
 3236 Guilhem Bichot	2010-11-26
      Fix for a bug: if a sub-statement shouldn't be traced but is inside a traced
      top-statement, the sub-statement's trace structures would be included
      inside the top-statement's trace instead of being invisible.
     @ mysql-test/r/optimizer_trace2.result
        Without the code fix, the trace of CALL would contain the trace
        of "select TRACE+NULL..." even though the latter one uses
        OPTIMIZER_TRACE (which shouldn't be traced).
     @ sql/opt_trace2server.cc
        Fix for the bug. The "allocated_here" part is for another bug (which
        could happen if running out of memory): we should free opt_trace
        only if we allocated it in this frame.

    added:
      mysql-test/r/optimizer_trace2.result
      mysql-test/t/optimizer_trace2.test
    modified:
      sql/opt_trace2server.cc
 3235 Guilhem Bichot	2010-11-24
      Implementing some TODOs:
      - renamed add_str*() and reviewed all calls of it
      - fixed "database"/"table" printouts in the trace (more uniform now)
      - test trace when the view/table/column/index' name contains \n and \t
      - added add_null()
      Misc: removed redundant "constant_tables" array. Fixed bug in detecting
      duplicate consecutive keys in a trace object.
     @ WL4800_TODO.txt
        deleting TODOs, adding others agreed during reviews
     @ mysql-test/r/optimizer_trace_no_prot.result
        "constant_tables" removed
     @ mysql-test/r/optimizer_trace_ps_prot.result
        "constant_tables" removed
     @ mysql-test/r/optimizer_trace_range.result
        escaping is done on the range now, gives correct trace
     @ mysql-test/t/optimizer_trace_charset.test
        * to check the validity of a trace, better get it in utf8 (that's what
        Python's json module wants) => "set names utf8"
        * test of \n and \t in view/table/column/index name
     @ sql/opt_range.cc
        add_alnum/add_utf8. add_null.
     @ sql/opt_trace.cc
        add_alnum/add_utf8. strcmp() was not detecting the case where
        the key is identical to the previous key but longer than sizeof(previous_key)
        (different length of previous_key and key made the equality false).
     @ sql/opt_trace.h
        add_str() renamed to add_alnum(). add_str_escaped() renamed to add_utf8().
        add_null() is added.
        A macro to avoid repeating this more than 10 times:
        trace_object.add_utf8("database", ...->s->db.str, ...->s->db.length)
        .add_utf8("table", ...->alias).
     @ sql/opt_trace2server.cc
        add_alnum/add_utf8
     @ sql/sql_delete.cc
        add_alnum/add_utf8.
     @ sql/sql_select.cc
        add_alnum/add_utf8. There were different sources used for finding the
        database and name of a table, here we standardize on TABLE::TABLE_SHARE::db
        and TABLE::alias. 'alias' is better than 'table_name' because in
        a query which uses the same table twice, the 'alias' is more unique.
        The old code also had a problem: sometimes it used the database
        of the first table of the join (s->join->tables_list->db) which
        may be wrong in a cross-database join.
        The "constant_tables" array is removed because it is redundant: constant
        tables are already listed in "records_estimation" with a mention of
        "const" or "system". Thus a big code block is re-indented.
     @ sql/sql_test.cc
        add_alnum/add_utf8.
     @ sql/sql_update.cc
        add_alnum/add_utf8.
     @ sql/sql_view.cc
        add_alnum/add_utf8. "database" instead of "db"; "view" instead of "name";
        this is to be symmetric of the "database"/"table" pair found in
        traces in sql_select.cc
     @ unittest/gunit/opt_trace-t.cc
        add_alnum/add_utf8.

    modified:
      WL4800_TODO.txt
      mysql-test/r/optimizer_trace_charset.result
      mysql-test/r/optimizer_trace_no_prot.result
      mysql-test/r/optimizer_trace_ps_prot.result
      mysql-test/r/optimizer_trace_range.result
      mysql-test/t/optimizer_trace_charset.test
      sql/opt_range.cc
      sql/opt_trace.cc
      sql/opt_trace.h
      sql/opt_trace2server.cc
      sql/sql_delete.cc
      sql/sql_select.cc
      sql/sql_test.cc
      sql/sql_update.cc
      sql/sql_view.cc
      unittest/gunit/opt_trace-t.cc
 3234 Guilhem Bichot	2010-11-23 [merge]
      merge of WL#5594 "tracing for range optimizer" into tree of WL#4800 "optimizer trace"

    removed:
      mysql-test/suite/ndb/r/optimizer_trace_range_opt_bug.result
      mysql-test/suite/ndb/t/optimizer_trace_range_opt_bug.test
    added:
      mysql-test/r/optimizer_trace_range.result
      mysql-test/t/optimizer_trace_range.test
    modified:
      WL4800_TODO.txt
      mysql-test/include/optimizer_trace.inc
      mysql-test/r/mysqld--help-notwin.result
      mysql-test/r/optimizer_trace_charset.result
      mysql-test/r/optimizer_trace_no_prot.result
      mysql-test/r/optimizer_trace_ps_prot.result
      mysql-test/suite/sys_vars/r/optimizer_trace_features_basic.result
      mysql-test/t/optimizer_trace_charset.test
      sql/handler.cc
      sql/opt_range.cc
      sql/opt_range.h
      sql/opt_trace.cc
      sql/opt_trace.h
      sql/opt_trace2server.cc
      sql/sql_delete.cc
      sql/sql_help.cc
      sql/sql_select.cc
      sql/sql_update.cc
      sql/sys_vars.cc
=== modified file 'WL4800_TODO.txt'
--- a/WL4800_TODO.txt	2010-11-17 12:27:39 +0000
+++ b/WL4800_TODO.txt	2010-12-21 07:34:33 +0000
@@ -1,19 +1,11 @@
 Short-term TODO list to remember for WL#4800
 ============================================
 
-avoid strlen() when appending constant strings.
-
 void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
 doesn't use "verbose".
 
-convert obscure names like range_select quick_condition_rows (etc?) to
-user-friendly descriptive self-explanatory names.
-
 see all added @todo
 
-About the prototype tracing of the range optimizer: either understand
-and improve it or delete it (Jorgen is working on it).
-
 My command to update the HTML Doxygen is:
 rsync -avz /m/doxygen/mysql-wl4800 [URL]:public_html
 
@@ -30,17 +22,40 @@ changes? any little change? maybe).
 Coding style:
 Make sure long code lines are wrapped.
 
-Sort out any charset-related problems (security-wise, for example: can
-I find a proper combination of client/server charsets so that creating
-the trace makes the server do wrong?). Review how escaping is done in
-opt_trace.cc.
+Misc security issues as discussed already.
 
 Review comments left:
 - in doc, mention DUMPFILE instead of OUTFILE
 - in changelog, mention /*select#*/; in doc, mention use of this (to
 decrypt what "id" is about in EXPLAIN).
 - more checks for non-unique keys?
-- investigate/test whether or not we need special case for
-  MYSQL_TYPE_BIT in print_key2
-- revert print_quick() and dbug_dump() to how they are in
-  opt_backporting
+
+Try to revert opt_range.cc and sql_test.cc as much as possible. Jorgen
+working on it.
+
+merge latest opt-backporting with fix for uninitialized keyuse, then
+fix all crashes of --opt-trace-protocol
+
+try to avoid the call to get_current_struct in opt_range.cc
+
+solve the problems of "one trace per row scanned" ("range checked for
+each record" and subqueries); one example is at the end of
+http://lists.mysql.com/commits/124599
+
+check save_in_field_no_warnings() in opt_range.cc: do we need to
+disable tracing there? see optimizer_trace_no_prot.result. Jorgen has
+maybe looked at this in his in-review subquery tracing patch.
+
+Push already written patches for
+- when view is merged, its WHERE clause is not seen in expanded query
+(solution: don't print expanded query in open_tables() but in
+JOIN::prepare(), when the clause has finally been merged)
+- some LEFT JOIN trigcond conditions may not be shown
+
+The optimizer may have second thoughts about which access method to
+use for a table. This should be traced. See example query (1) where
+the trace says that ref-access is best but we change our mind and use
+range access anyway.
+(1)CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b), KEY b (b));
+   INSERT INTO t1 VALUES (1,1),(1,2),(1,0),(1,3);
+   SELECT MAX(b), a FROM t1 WHERE b < 2 AND a = 1 GROUP BY a;

=== modified file 'WL4800_validate_json.py'
--- a/WL4800_validate_json.py	2010-10-05 10:29:43 +0000
+++ b/WL4800_validate_json.py	2010-11-15 21:05:48 +0000
@@ -42,8 +42,16 @@ def check(trace, first_trace_line):
         parsed = json.loads(s)
     except:
         print "parse error at line", first_trace_line
-        print sys.exc_info()
-        print s
+        error = str(sys.exc_info())
+        print error
+        # if there is a character position specified, put a mark ('&')
+        # in front of this character
+        matchobj = re.search(r"ValueError\('Invalid control character at: line \d+ column \d+ \(char (\d+)\)'", error)
+        if matchobj:
+            first_error_char = int(matchobj.group(1))
+            print s[:first_error_char] + "&" + s[first_error_char:]
+        else:
+            print s
         retcode = 1
         print
         return

=== modified file 'mysql-test/include/optimizer_trace.inc'
--- a/mysql-test/include/optimizer_trace.inc	2010-11-11 13:25:53 +0000
+++ b/mysql-test/include/optimizer_trace.inc	2010-11-26 16:16:31 +0000
@@ -59,13 +59,13 @@ set optimizer_trace="one_line=off,end_ma
 EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 select * from information_schema.OPTIMIZER_TRACE;
 
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 select * from information_schema.OPTIMIZER_TRACE;
 
 set @@session.optimizer_trace="enabled=off";
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* bug if you see this*/ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 # should not see last statement but previous
-select * from information_schema.OPTIMIZER_TRACE;
+select QUERY from information_schema.OPTIMIZER_TRACE;
 
 set @@session.optimizer_trace="enabled=on";
 
@@ -82,12 +82,12 @@ select * from information_schema.OPTIMIZ
 select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
 select length(@trace);
 # The trace above has length:
-# - >8400 in normal mode
-# - <8400 in ps-protocol mode (because IN->EXISTS is done at PREPARE
+# - >9000 in normal mode
+# - <9000 in ps-protocol mode (because IN->EXISTS is done at PREPARE
 # and we trace only EXECUTE)
 # - So in normal mode, the lines below verify truncation,
 # whereas in ps-protocol mode they verify non-truncation.
-set optimizer_trace_max_mem_size=8400;
+set optimizer_trace_max_mem_size=9000;
 select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
 SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
 select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
@@ -156,9 +156,6 @@ select @@optimizer_trace_features;
 set @@optimizer_trace_features="greedy_search=off";
 explain select * from t1,t2;
 select * from information_schema.OPTIMIZER_TRACE;
-set @@optimizer_trace_features="greedy_search=on,misc=off";
-explain select * from t1,t2;
-select * from information_schema.OPTIMIZER_TRACE;
 set @@optimizer_trace_features=default;
 set @@session.optimizer_prune_level=default;
 drop table t1, t2;
@@ -332,6 +329,11 @@ select 2;
 select 3;
 select 4;
 select 5;
+# In normal mode, each SELECT is a standalone statement and generates
+# one trace: so 3rd and 4th trace means 3rd and 4th SELECT.
+# In ps-protocol mode, each SELECT is two statements: PREPARE and
+# EXECUTE; each of the two creates one trace; so 3rd and 4th trace
+# means 2nd SELECT (preparation) and 2nd SELECT again (execution).
 select * from information_schema.OPTIMIZER_TRACE;
 set optimizer_trace_offset=-2,optimizer_trace_limit=2;
 # should be empty
@@ -389,14 +391,23 @@ select s, f1() from t2 order by s desc|
 select * from information_schema.OPTIMIZER_TRACE|
 select * from t6 where d in (select f1() from t2 where s="c")|
 select * from information_schema.OPTIMIZER_TRACE|
-# Want to see the top and invoked sub-statements:
-set optimizer_trace_offset=-4, optimizer_trace_limit=4|
+# Want to see the top and invoked sub-statements; this means 7 traces:
+# 1 top statement + two executions of f1() (there is one
+# execution inside the range optimizer and one "normal" execution);
+# 3 sub-statements in the stored function: 1+2*3=7.
+set optimizer_trace_offset=-7, optimizer_trace_limit=7|
 select @@optimizer_trace_offset, @@optimizer_trace_limit|
 select * from t6 where d in (select f1() from t2 where s="c")|
 select * from information_schema.OPTIMIZER_TRACE|
 # Want to see the DELETE (invoked sub-statement):
 set optimizer_trace_offset=2, optimizer_trace_limit=1|
 select * from t6 where d in (select f1() from t2 where s="c")|
+# In normal mode, we have traces for the top SELECT, then the
+# function's INSERT then the function's DELETE, so DELETE is the
+# third trace, which we see.
+# In ps-protocol mode, we have PREPARE and EXECUTE for the top SELECT
+# (two traces); execution will generate the function's INSERT and
+# DELETE; so INSERT is the third trace, which we see.
 select * from information_schema.OPTIMIZER_TRACE|
 set optimizer_trace_offset=default, optimizer_trace_limit=default|
 
@@ -424,7 +435,8 @@ delimiter ;|
 
 # PREPARE/EXECUTE/EXECUTE
 prepare stmt from 'call p1(?)';
-select * from information_schema.OPTIMIZER_TRACE;
+# PREPARE CALL is not traced, we should see previous statement:
+select QUERY from information_schema.OPTIMIZER_TRACE;
 set @param="c";
 execute stmt using @param;
 select TRACE into @trace from information_schema.OPTIMIZER_TRACE;
@@ -501,6 +513,14 @@ select 1 union select 2;
 set optimizer_switch='default,index_merge=on,index_merge=off,default';
 select @@optimizer_switch;
 
+# Test for long query (1070 chars)
+--disable_query_log
+--disable_result_log
+select "abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col;
+--enable_result_log
+--enable_query_log
+select * from information_schema.OPTIMIZER_TRACE;
+
 drop table t1,t2;
 DROP TABLE t5,t6;
 set optimizer_trace=default;

=== modified file 'mysql-test/r/mysqld--help-notwin.result'
--- a/mysql-test/r/mysqld--help-notwin.result	2010-11-17 12:27:39 +0000
+++ b/mysql-test/r/mysqld--help-notwin.result	2010-12-19 14:24:03 +0000
@@ -418,8 +418,8 @@ The following options may be given as th
  Enables/disables tracing of selected features of the
  Optimizer:
  optimizer_trace_features=option=val[,option=val...],
- where option is one of {misc, greedy_search,
- range_optimizer} and val is one of {on, off, default}
+ where option is one of {greedy_search, range_optimizer}
+ and val is one of {on, off, default}
  --optimizer-trace-limit=# 
  Maximum number of shown optimizer traces
  --optimizer-trace-max-mem-size=# 
@@ -871,7 +871,7 @@ optimizer-prune-level 1
 optimizer-search-depth 62
 optimizer-switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on,mrr=on,mrr_cost_based=off,index_condition_pushdown=on
 optimizer-trace 
-optimizer-trace-features misc=on,greedy_search=on,range_optimizer=on
+optimizer-trace-features greedy_search=on,range_optimizer=on
 optimizer-trace-limit 1
 optimizer-trace-max-mem-size 16384
 optimizer-trace-offset -1

=== added file 'mysql-test/r/optimizer_trace2.result'
--- a/mysql-test/r/optimizer_trace2.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_trace2.result	2010-12-19 14:24:03 +0000
@@ -0,0 +1,171 @@
+set optimizer_trace="enabled=on,end_marker=on";
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+create function f1(arg char(1)) returns int
+begin
+declare res int;
+declare dummy varchar(1);
+select 1 into res from dual;
+select TRACE+NULL into dummy from information_schema.OPTIMIZER_TRACE limit 1;
+select 2 into res from dual;
+return 3;
+end|
+select f1("c")|
+f1("c")
+3
+
+select distinct QUERY from information_schema.OPTIMIZER_TRACE|
+QUERY
+select f1("c")
+select 1 into res from dual
+select 2 into res from dual
+set optimizer_trace_offset=default, optimizer_trace_limit=default;
+drop function f1;
+create table t1(a int, b int);
+create view v1 as select a from t1;
+select VIEW_DEFINITION from information_schema.VIEWS
+where TABLE_SCHEMA="test" and TABLE_NAME="v1";
+VIEW_DEFINITION
+select `test`.`t1`.`a` AS `a` from `test`.`t1`
+select locate("\"view\": \"v1\"", TRACE) != 0
+from information_schema.OPTIMIZER_TRACE;
+locate("\"view\": \"v1\"", TRACE) != 0
+1
+drop table t1;
+drop view v1;
+create table t1 (a bit(5), key(a));
+insert into t1 values(b'00000'),(b'01101');
+select cast(a as unsigned) from t1 where a > b'01100';
+cast(a as unsigned)
+13
+select TRACE from information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select cast(`a` as unsigned) AS `cast(a as unsigned)` from `test`.`t1` where (`a` > 0x0c)"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "(`test`.`t1`.`a` > 0x0c)",
+              "after_equality_propagation": "(`test`.`t1`.`a` > 0x0c)",
+              "after_constant_propagation": "(`test`.`t1`.`a` > 0x0c)",
+              "after_trivial_conditions_removal": "(`test`.`t1`.`a` > 0x0c)"
+            } /* condition_processing */
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ] /* ref-optimizer-key-uses */
+          },
+          {
+            "records_estimation": [
+              {
+                "database": "test",
+                "table": "t1",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "a",
+                      "usable": true,
+                      "key_parts": [
+                        "a"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_covering_index_scan": {
+                    "index": "a",
+                    "cost": 1.4175,
+                    "chosen": true
+                  } /* best_covering_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "a",
+                        "ranges": [
+                          "12 < a"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 2,
+                        "cost": 3.41,
+                        "rowid_ordered": false,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */
+                } /* range_analysis */
+              }
+            ] /* records_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "database": "test",
+                "table": "t1",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_join_cache": true,
+                      "records": 2,
+                      "cost": 2.0034,
+                      "chosen": true
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.0034,
+                "records_for_plan": 2,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "(`test`.`t1`.`a` > 0x0c)",
+              "attached_conditions": [
+                {
+                  "database": "test",
+                  "table": "t1",
+                  "attached": "(`test`.`t1`.`a` > 0x0c)"
+                }
+              ] /* attached_conditions */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "database": "test",
+                "table": "t1",
+                "scan_type": "index"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    }
+  ] /* steps */
+}
+drop table t1;

=== modified file 'mysql-test/r/optimizer_trace_charset.result'
--- a/mysql-test/r/optimizer_trace_charset.result	2010-11-22 09:59:17 +0000
+++ b/mysql-test/r/optimizer_trace_charset.result	2010-11-24 18:54:26 +0000
@@ -29,9 +29,6 @@ explain extended select '��� from t1 
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t1"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -78,9 +75,6 @@ explain extended select 'ÁÂÃÄÅ' fro
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t1"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -115,14 +109,15 @@ col
 select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
 (@query:=QUERY)+NULL	(@trace:=TRACE)+NULL
 NULL	NULL
+set names utf8;
 select @query, @trace;
 @query	@trace
-select * from v1 where v1.col = '���	{
+select * from v1 where v1.col = 'ÁÂÃÄÅ'	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "materialized": true
       } /* view */
@@ -142,9 +137,6 @@ select * from v1 where v1.col = '���	
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-              "t1"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -194,9 +186,6 @@ select * from v1 where v1.col = '���	
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "v1"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -225,15 +214,20 @@ select * from v1 where v1.col = '���	
 }
 drop table t1;
 drop view v1;
+set names latin1;
 create table t1(c char(4) primary key);
 insert into t1 values ('aaa'), ('��');
 select * from t1 where c < '���;
 c
 aaa
 ��
-select query, trace from information_schema.OPTIMIZER_TRACE;
-query	trace
-select * from t1 where c < '���	{
+select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
+(@query:=QUERY)+NULL	(@trace:=TRACE)+NULL
+NULL	NULL
+set names utf8;
+select @query, @trace;
+@query	@trace
+select * from t1 where c < 'ÁÂÃÄÅ'	{
   "steps": [
     {
       "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where (`c` < '?????')"
@@ -263,8 +257,6 @@ select * from t1 where c < '���	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -297,7 +289,7 @@ select * from t1 where c < '    "index": "PRIMARY",
                         "ranges": [
-                          "c <= ��"
+                          "c <= ÁÂÃÄ"
                         ] /* ranges */,
                         "index_only": true,
                         "records": 2,
@@ -365,4 +357,168 @@ select * from t1 where c < '���	{
   ] /* steps */
 }
 drop table t1;
+create table `t
+1	a`(`col
+1	a` int, index `index
+1	a` (`col
+1	a`));
+insert into `t
+1	a` values(2),(3);
+create view `v
+1	a` as select * from `t
+1	a`;
+select `col
+1	a` from `v
+1	a` where `col
+1	a` < 6;
+col
+1	a
+2
+3
+select query, trace from information_schema.OPTIMIZER_TRACE;
+query	trace
+select `col
+1	a` from `v
+1	a` where `col
+1	a` < 6	{
+  "steps": [
+    {
+      "view": {
+        "database": "test",
+        "view": "v\n1\ta",
+        "in_select#": 1,
+        "merged": true
+      } /* view */
+    },
+    {
+      "expanded_query": "/* select#1 */ select `col\n1\ta` AS `col\n1\ta` from (`test`.`t\n1\ta`) where (`col\n1\ta` < 6)"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)",
+              "after_equality_propagation": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)",
+              "after_constant_propagation": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)",
+              "after_trivial_conditions_removal": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)"
+            } /* condition_processing */
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ] /* ref-optimizer-key-uses */
+          },
+          {
+            "records_estimation": [
+              {
+                "database": "test",
+                "table": "t\n1\ta",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "index\n1\ta",
+                      "usable": true,
+                      "key_parts": [
+                        "col\n1\ta"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_covering_index_scan": {
+                    "index": "index\n1\ta",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_covering_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "index\n1\ta",
+                        "ranges": [
+                          "NULL < col\n1\ta < 6"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": false,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */
+                } /* range_analysis */
+              }
+            ] /* records_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "database": "test",
+                "table": "t\n1\ta",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_join_cache": true,
+                      "records": 1,
+                      "cost": 2.2034,
+                      "chosen": true
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.2034,
+                "records_for_plan": 1,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)",
+              "attached_conditions": [
+                {
+                  "database": "test",
+                  "table": "t\n1\ta",
+                  "attached": "(`test`.`t\n1\ta`.`col\n1\ta` < 6)"
+                }
+              ] /* attached_conditions */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "database": "test",
+                "table": "t\n1\ta",
+                "scan_type": "index"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    }
+  ] /* steps */
+}
+drop table `t
+1	a`;
+drop view `v
+1	a`;
 set optimizer_trace=default;

=== modified file 'mysql-test/r/optimizer_trace_no_prot.result'
--- a/mysql-test/r/optimizer_trace_no_prot.result	2010-11-22 09:59:17 +0000
+++ b/mysql-test/r/optimizer_trace_no_prot.result	2010-11-26 16:16:31 +0000
@@ -37,9 +37,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ],
             "records_estimation": [
               {
                 "database": "test",
@@ -86,8 +83,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
             ]
           },
           {
-            "constant_tables": [
-            ],
             "records_estimation": [
               {
                 "database": "test",
@@ -134,18 +129,18 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-50.3069
+50.1007
 set optimizer_trace="one_line=on";
 SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 ;
 RESULT
 NULL
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5	{"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = `c`)) AS `RESULT` from `test`.`t5`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["t5"],"records_estimation": [{"database": "test","table": "t5","records": 1,"cost": 1,"table_type": "system"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}},{"refine_plan": []}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`t6`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "t6.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"database": "test","table": "t6","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","usable": true,"key_parts": ["d"]}],"best_covering_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_condition": {"table": "t6","field": "d","cause": "comparison_with_null_always_false"},"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
+SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5	{"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = `c`)) AS `RESULT` from `test`.`t5`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"records_estimation": [{"database": "test","table": "t5","records": 1,"cost": 1,"table_type": "system"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}},{"refine_plan": []}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`t6`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "t6.d= NULL","null_rejecting": true}]},{"records_estimation": [{"database": "test","table": "t6","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","usable": true,"key_parts": ["d"]}],"best_covering_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_condition": {"table": "t6","field": "d","cause": "comparison_with_null_always_false"},"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-6.0185
+6.0792
 set optimizer_trace="one_line=off,end_marker=on";
 EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
@@ -177,9 +172,6 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -226,8 +218,6 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -271,12 +261,12 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
     }
   ] /* steps */
 }	0	0
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
 NULL
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5	{
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5	{
   "steps": [
     {
       "expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = ifnull(`c`,NULL))) AS `RESULT` from `test`.`t5`"
@@ -300,9 +290,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -349,8 +336,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -395,15 +380,12 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
   ] /* steps */
 }	0	0
 set @@session.optimizer_trace="enabled=off";
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* bug if you see this*/ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
 NULL
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-set @@session.optimizer_trace="enabled=off"	{
-  "steps": [
-  ] /* steps */
-}	0	0
+select QUERY from information_schema.OPTIMIZER_TRACE;
+QUERY
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5
 set @@session.optimizer_trace="enabled=on";
 SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
@@ -441,9 +423,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -490,8 +469,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -555,8 +532,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -610,8 +585,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -767,9 +740,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -846,8 +816,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
               "select#": "fake",
               "steps": [
                 {
-                  "constant_tables": [
-                  ] /* constant_tables */,
                   "records_estimation": [
                     {
                       "database": "",
@@ -918,8 +886,8 @@ select (@query:=QUERY)+NULL, (@trace:=TR
 NULL	NULL
 select length(@trace);
 length(@trace)
-9257
-set optimizer_trace_max_mem_size=8400;
+9086
+set optimizer_trace_max_mem_size=9000;
 select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
 length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
 1
@@ -927,7 +895,7 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
 c
 select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
 (@missing_bytes:=missing_bytes_beyond_max_mem_size)
-972
+208
 select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
 (@query2:=QUERY)+NULL	(@trace2:=TRACE)+NULL
 NULL	NULL
@@ -935,7 +903,7 @@ select length(@trace2),
 (length(@trace2) + @missing_bytes) = length(@trace),
 @query2 = @query;
 length(@trace2)	(length(@trace2) + @missing_bytes) = length(@trace)	@query2 = @query
-8285	1	1
+8878	1	1
 select length(@query2) + length(@trace2)
 between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100);
 length(@query2) + length(@trace2)
@@ -1022,9 +990,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1283,9 +1248,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1340,8 +1302,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1504,8 +1464,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1568,8 +1526,6 @@ explain extended select * from t1 where 
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1682,8 +1638,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1746,8 +1700,6 @@ explain extended select * from t1 where 
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1877,8 +1829,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1954,8 +1904,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2084,8 +2032,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2161,8 +2107,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2252,8 +2196,6 @@ explain select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2389,7 +2331,7 @@ explain select * from t1,t2	{
 }	0	0
 select @@optimizer_trace_features;
 @@optimizer_trace_features
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on
 set @@optimizer_trace_features="greedy_search=off";
 explain select * from t1,t2;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
@@ -2414,8 +2356,6 @@ explain select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2474,14 +2414,6 @@ explain select * from t1,t2	{
     }
   ] /* steps */
 }	0	0
-set @@optimizer_trace_features="greedy_search=on,misc=off";
-explain select * from t1,t2;
-id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	2	
-1	SIMPLE	t1	ALL	NULL	NULL	NULL	NULL	3	Using join buffer (BNL, regular buffers)
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-explain select * from t1,t2		0	0
 set @@optimizer_trace_features=default;
 set @@session.optimizer_prune_level=default;
 drop table t1, t2;
@@ -2551,7 +2483,7 @@ where a1 in (select b1 from t2_16 where 
                     "from": "IN (SELECT)",
                     "to": "materialization",
                     "chosen": false,
-                    "cause": "field types"
+                    "cause": "field_types"
                   } /* transformation */
                 },
                 {
@@ -2586,8 +2518,6 @@ where a1 in (select b1 from t2_16 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2663,8 +2593,6 @@ where a1 in (select b1 from t2_16 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2803,8 +2731,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2935,8 +2861,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3038,8 +2962,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3115,8 +3037,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3186,8 +3106,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -3343,8 +3261,6 @@ concat(c1,'y') IN
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3423,8 +3339,6 @@ concat(c1,'y') IN
         "select#": 3,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3487,8 +3401,6 @@ concat(c1,'y') IN
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3576,10 +3488,6 @@ select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3709,11 +3617,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t3",
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3840,11 +3743,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t3",
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3955,8 +3853,6 @@ select * from t1 left join t2 on t2.a=50
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4122,8 +4018,6 @@ select * from t1 where (t1.a,t1.b) not i
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4207,8 +4101,6 @@ select * from t1 where (t1.a,t1.b) not i
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4313,8 +4205,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4646,8 +4536,6 @@ insert into t6 select * from t6 where d>
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4780,9 +4668,6 @@ update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4928,9 +4813,6 @@ delete t6 from t5, t6 where d>7000	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5205,8 +5087,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5290,8 +5170,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5372,8 +5250,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5433,14 +5309,387 @@ select sum(data) into ret from t1	{
     }
   ] /* steps */
 }	0	0
-set optimizer_trace_offset=-4, optimizer_trace_limit=4|
+set optimizer_trace_offset=-7, optimizer_trace_limit=7|
 select @@optimizer_trace_offset, @@optimizer_trace_limit|
 @@optimizer_trace_offset	@@optimizer_trace_limit
--4	4
+-7	7
 select * from t6 where d in (select f1() from t2 where s="c")|
 d
 select * from information_schema.OPTIMIZER_TRACE|
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
+select * from t6 where d in (select f1() from t2 where s="c")	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t6` where `d` in (/* select#2 */ select `f1`() from `test`.`t2` where (`s` = 'c'))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "join_preparation": {
+              "select#": 2,
+              "steps": [
+                {
+                  "transformation": {
+                    "select#": 2,
+                    "from": "IN (SELECT)",
+                    "to": "semijoin",
+                    "chosen": true
+                  } /* transformation */
+                }
+              ] /* steps */
+            } /* join_preparation */
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "transformation": {
+              "select#": 2,
+              "from": "IN (SELECT)",
+              "to": "semijoin",
+              "chosen": true
+            } /* transformation */
+          },
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "(1 and (`test`.`t2`.`s` = 'c') and (`test`.`t6`.`d` = `f1`()))",
+              "after_equality_propagation": "(1 and multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))",
+              "after_constant_propagation": "(1 and multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))",
+              "after_trivial_conditions_removal": "(multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+            } /* condition_processing */
+          },
+          {
+            "ref-optimizer-key-uses": [
+              {
+                "condition": "t6.d= `f1`()",
+                "null_rejecting": false
+              }
+            ] /* ref-optimizer-key-uses */
+          },
+          {
+            "records_estimation": [
+              {
+                "database": "test",
+                "table": "t6",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "usable": true,
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_covering_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_covering_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_single_table"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "3 <= d <= 3"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */
+                } /* range_analysis */
+              },
+              {
+                "database": "test",
+                "table": "t2",
+                "table_scan": {
+                  "records": 3,
+                  "cost": 2
+                } /* table_scan */
+              }
+            ] /* records_estimation */
+          },
+          {
+            "pulled_out_semijoin_tables": [
+            ] /* pulled_out_semijoin_tables */
+          },
+          {
+            "execution_plan_for_potential_materialization": {
+              "steps": [
+                {
+                  "considered_execution_plans": [
+                    {
+                      "database": "test",
+                      "table": "t2",
+                      "best_access_path": {
+                        "considered_access_paths": [
+                          {
+                            "access_type": "scan",
+                            "using_join_cache": true,
+                            "records": 3,
+                            "cost": 2.0212,
+                            "chosen": true
+                          }
+                        ] /* considered_access_paths */
+                      } /* best_access_path */,
+                      "cost_for_plan": 2.0212,
+                      "records_for_plan": 3,
+                      "semijoin_strategy_choice": [
+                      ] /* semijoin_strategy_choice */,
+                      "chosen": true
+                    }
+                  ] /* considered_execution_plans */
+                }
+              ] /* steps */
+            } /* execution_plan_for_potential_materialization */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "database": "test",
+                "table": "t2",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_join_cache": true,
+                      "records": 3,
+                      "cost": 2.0212,
+                      "chosen": true
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.0212,
+                "records_for_plan": 3,
+                "semijoin_strategy_choice": [
+                ] /* semijoin_strategy_choice */,
+                "rest_of_plan": [
+                  {
+                    "database": "test",
+                    "table": "t6",
+                    "best_access_path": {
+                      "considered_access_paths": [
+                        {
+                          "access_type": "ref",
+                          "index": "d",
+                          "records": 1,
+                          "cost": 3,
+                          "chosen": true
+                        },
+                        {
+                          "access_type": "scan",
+                          "using_join_cache": true,
+                          "records": 1,
+                          "cost": 2.6076,
+                          "chosen": true
+                        }
+                      ] /* considered_access_paths */
+                    } /* best_access_path */,
+                    "cost_for_plan": 4.6289,
+                    "records_for_plan": 3,
+                    "semijoin_strategy_choice": [
+                      {
+                        "strategy": "DuplicatesWeedout",
+                        "cost": 5.2289,
+                        "records": 1,
+                        "duplicate_tables_left": true,
+                        "chosen": true
+                      }
+                    ] /* semijoin_strategy_choice */,
+                    "chosen": true
+                  }
+                ] /* rest_of_plan */
+              },
+              {
+                "database": "test",
+                "table": "t6",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "d",
+                      "records": 1,
+                      "cost": 1,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "scan",
+                      "cost": 2,
+                      "records": 4,
+                      "cause": "cost",
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 1,
+                "records_for_plan": 1,
+                "semijoin_strategy_choice": [
+                ] /* semijoin_strategy_choice */,
+                "rest_of_plan": [
+                  {
+                    "database": "test",
+                    "table": "t2",
+                    "best_access_path": {
+                      "considered_access_paths": [
+                        {
+                          "access_type": "scan",
+                          "using_join_cache": true,
+                          "records": 3,
+                          "cost": 2.0213,
+                          "chosen": true
+                        }
+                      ] /* considered_access_paths */
+                    } /* best_access_path */,
+                    "cost_for_plan": 3.0213,
+                    "records_for_plan": 3,
+                    "semijoin_strategy_choice": [
+                      {
+                        "strategy": "FirstMatch",
+                        "recompute_best_access_paths": {
+                          "cause": "join_buffering_not_possible",
+                          "tables": [
+                            {
+                              "database": "test",
+                              "table": "t2",
+                              "best_access_path": {
+                                "considered_access_paths": [
+                                  {
+                                    "access_type": "scan",
+                                    "using_join_cache": true,
+                                    "records": 3,
+                                    "cost": 2.0213,
+                                    "chosen": true
+                                  }
+                                ] /* considered_access_paths */
+                              } /* best_access_path */
+                            }
+                          ] /* tables */
+                        } /* recompute_best_access_paths */,
+                        "cost": 3.0213,
+                        "records": 1,
+                        "chosen": true
+                      },
+                      {
+                        "strategy": "MaterializationLookup",
+                        "cost": 3.2212,
+                        "records": 1,
+                        "duplicate_tables_left": false,
+                        "chosen": false
+                      },
+                      {
+                        "strategy": "DuplicatesWeedout",
+                        "cost": 3.6213,
+                        "records": 1,
+                        "duplicate_tables_left": false,
+                        "chosen": false
+                      }
+                    ] /* semijoin_strategy_choice */,
+                    "chosen": true
+                  }
+                ] /* rest_of_plan */
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "reconsidering_access_paths_for_semijoin": {
+              "strategy": "FirstMatch",
+              "database": "test",
+              "table": "t2",
+              "best_access_path": {
+                "considered_access_paths": [
+                  {
+                    "access_type": "scan",
+                    "records": 3,
+                    "cost": 2.0212,
+                    "chosen": true
+                  }
+                ] /* considered_access_paths */
+              } /* best_access_path */
+            } /* reconsidering_access_paths_for_semijoin */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))",
+              "attached_conditions": [
+                {
+                  "database": "test",
+                  "table": "t6",
+                  "attached": "(`test`.`t6`.`d` = `f1`())"
+                },
+                {
+                  "database": "test",
+                  "table": "t2",
+                  "attached": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))"
+                }
+              ] /* attached_conditions */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "database": "test",
+                "table": "t6"
+              },
+              {
+                "database": "test",
+                "table": "t2",
+                "scan_type": "table"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    }
+  ] /* steps */
+}	0	0
+insert into t1 values("z",0)	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select  from dual"
+    }
+  ] /* steps */
+}	0	0
+delete from t1 where id="z"	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
+    },
+    {
+      "database": "test",
+      "table": "t1",
+      "range_analysis": {
+        "table_scan": {
+          "records": 3,
+          "cost": 4.7154
+        } /* table_scan */
+      } /* range_analysis */
+    }
+  ] /* steps */
+}	0	0
 select sum(data) into ret from t1	{
   "steps": [
     {
@@ -5458,8 +5707,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5560,8 +5807,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5689,8 +5934,6 @@ select d+1 into res from t6 where d= NAM
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5758,8 +6001,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5829,12 +6070,9 @@ c	3	3
 3	100	200
 3	100	200
 prepare stmt from 'call p1(?)';
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-prepare stmt from 'call p1(?)'	{
-  "steps": [
-  ] /* steps */
-}	0	0
+select QUERY from information_schema.OPTIMIZER_TRACE;
+QUERY
+select * from t2
 set @param="c";
 execute stmt using @param;
 Warnings:
@@ -5876,8 +6114,6 @@ select @trace;
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6005,8 +6241,6 @@ select d into res from t6 where d in (se
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6305,8 +6539,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6407,8 +6639,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6468,10 +6698,6 @@ select sum(data) into ret from t1	{
     }
   ] /* steps */
 }	0	0
-SET optimizer_trace="enabled=off"	{
-  "steps": [
-  ] /* steps */
-}	0	0
 select @@optimizer_trace|
 @@optimizer_trace
 enabled=off,end_marker=on,one_line=off
@@ -6490,8 +6716,8 @@ explain select * from v1 where id="b"	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "merged": true
       } /* view */
@@ -6524,8 +6750,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6592,8 +6816,8 @@ insert into v1 values("z", 100)	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "merged": true
       } /* view */
@@ -6610,8 +6834,8 @@ delete from v1 where data=100	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "merged": true
       } /* view */
@@ -6621,7 +6845,7 @@ delete from v1 where data=100	{
     },
     {
       "database": "test",
-      "table": "v1",
+      "table": "t1",
       "range_analysis": {
         "table_scan": {
           "records": 3,
@@ -6643,8 +6867,8 @@ explain select * from v1 where id="b"	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "materialized": true
       } /* view */
@@ -6677,8 +6901,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6761,8 +6983,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -6860,8 +7080,6 @@ VARIABLE_NAME="optimizer_trace"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "information_schema",
@@ -6972,8 +7190,6 @@ select TRACE into dumpfile 'MYSQLTEST_VA
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ],
             "records_estimation": [
               {
                 "database": "",
@@ -7037,6 +7253,29 @@ ERROR 42000: Variable 'optimizer_switch'
 select @@optimizer_switch;
 @@optimizer_switch
 index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on,mrr=on,mrr_cost_based=off,index_condition_pushdown=on
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
+select "abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select 'abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def' AS `col`"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    }
+  ]
+}	0	0
 drop table t1,t2;
 DROP TABLE t5,t6;
 set optimizer_trace=default;

=== modified file 'mysql-test/r/optimizer_trace_ps_prot.result'
--- a/mysql-test/r/optimizer_trace_ps_prot.result	2010-11-22 09:59:17 +0000
+++ b/mysql-test/r/optimizer_trace_ps_prot.result	2010-11-26 16:16:31 +0000
@@ -37,9 +37,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ],
             "records_estimation": [
               {
                 "database": "test",
@@ -86,8 +83,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
             ]
           },
           {
-            "constant_tables": [
-            ],
             "records_estimation": [
               {
                 "database": "test",
@@ -134,18 +129,18 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-50.3069
+50.1007
 set optimizer_trace="one_line=on";
 SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 ;
 RESULT
 NULL
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5	{"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = `c`)) AS `RESULT` from `test`.`t5`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["t5"],"records_estimation": [{"database": "test","table": "t5","records": 1,"cost": 1,"table_type": "system"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}},{"refine_plan": []}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`t6`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "t6.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"database": "test","table": "t6","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","usable": true,"key_parts": ["d"]}],"best_covering_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_condition": {"table": "t6","field": "d","cause": "comparison_with_null_always_false"},"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
+SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5	{"steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = `c`)) AS `RESULT` from `test`.`t5`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"records_estimation": [{"database": "test","table": "t5","records": 1,"cost": 1,"table_type": "system"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}},{"refine_plan": []}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`t6`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`t6`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "t6.d= NULL","null_rejecting": true}]},{"records_estimation": [{"database": "test","table": "t6","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","usable": true,"key_parts": ["d"]}],"best_covering_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_condition": {"table": "t6","field": "d","cause": "comparison_with_null_always_false"},"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-6.0185
+6.0792
 set optimizer_trace="one_line=off,end_marker=on";
 EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
@@ -177,9 +172,6 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -226,8 +218,6 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -271,12 +261,12 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
     }
   ] /* steps */
 }	0	0
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
 NULL
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5	{
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5	{
   "steps": [
     {
       "expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`d` = ifnull(`c`,NULL))) AS `RESULT` from `test`.`t5`"
@@ -300,9 +290,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -349,8 +336,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -395,15 +380,12 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
   ] /* steps */
 }	0	0
 set @@session.optimizer_trace="enabled=off";
-SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
+SELECT /* bug if you see this*/ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
 NULL
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-set @@session.optimizer_trace="enabled=off"	{
-  "steps": [
-  ] /* steps */
-}	0	0
+select QUERY from information_schema.OPTIMIZER_TRACE;
+QUERY
+SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5
 set @@session.optimizer_trace="enabled=on";
 SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
 RESULT
@@ -441,9 +423,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -490,8 +469,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -555,8 +532,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -610,8 +585,6 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -751,9 +724,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -830,8 +800,6 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
               "select#": "fake",
               "steps": [
                 {
-                  "constant_tables": [
-                  ] /* constant_tables */,
                   "records_estimation": [
                     {
                       "database": "",
@@ -902,16 +870,16 @@ select (@query:=QUERY)+NULL, (@trace:=TR
 NULL	NULL
 select length(@trace);
 length(@trace)
-8802
-set optimizer_trace_max_mem_size=8400;
+8631
+set optimizer_trace_max_mem_size=9000;
 select length(@query)+length(@trace) > @@optimizer_trace_max_mem_size;
 length(@query)+length(@trace) > @@optimizer_trace_max_mem_size
-1
+0
 SELECT * FROM t5 WHERE 5 IN (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null));
 c
 select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
 (@missing_bytes:=missing_bytes_beyond_max_mem_size)
-517
+0
 select (@query2:=QUERY)+NULL,(@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
 (@query2:=QUERY)+NULL	(@trace2:=TRACE)+NULL
 NULL	NULL
@@ -919,12 +887,12 @@ select length(@trace2),
 (length(@trace2) + @missing_bytes) = length(@trace),
 @query2 = @query;
 length(@trace2)	(length(@trace2) + @missing_bytes) = length(@trace)	@query2 = @query
-8285	1	1
+8631	1	1
 select length(@query2) + length(@trace2)
 between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100);
 length(@query2) + length(@trace2)
 between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100)
-1
+0
 select instr(@trace, @trace2) = 1;
 instr(@trace, @trace2) = 1
 1
@@ -1006,9 +974,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1267,9 +1232,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1324,8 +1286,6 @@ explain SELECT c FROM t5 where c+1 in (s
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1488,8 +1448,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1552,8 +1510,6 @@ explain extended select * from t1 where 
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1666,8 +1622,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1730,8 +1684,6 @@ explain extended select * from t1 where 
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1861,8 +1813,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1938,8 +1888,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2068,8 +2016,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2145,8 +2091,6 @@ explain extended select * from t1 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2236,8 +2180,6 @@ explain select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2373,7 +2315,7 @@ explain select * from t1,t2	{
 }	0	0
 select @@optimizer_trace_features;
 @@optimizer_trace_features
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on
 set @@optimizer_trace_features="greedy_search=off";
 explain select * from t1,t2;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
@@ -2398,8 +2340,6 @@ explain select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2458,14 +2398,6 @@ explain select * from t1,t2	{
     }
   ] /* steps */
 }	0	0
-set @@optimizer_trace_features="greedy_search=on,misc=off";
-explain select * from t1,t2;
-id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	2	
-1	SIMPLE	t1	ALL	NULL	NULL	NULL	NULL	3	Using join buffer (BNL, regular buffers)
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-explain select * from t1,t2		0	0
 set @@optimizer_trace_features=default;
 set @@session.optimizer_prune_level=default;
 drop table t1, t2;
@@ -2535,7 +2467,7 @@ where a1 in (select b1 from t2_16 where 
                     "from": "IN (SELECT)",
                     "to": "materialization",
                     "chosen": false,
-                    "cause": "field types"
+                    "cause": "field_types"
                   } /* transformation */
                 },
                 {
@@ -2570,8 +2502,6 @@ where a1 in (select b1 from t2_16 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2647,8 +2577,6 @@ where a1 in (select b1 from t2_16 where 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2787,8 +2715,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2919,8 +2845,6 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3022,8 +2946,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3099,8 +3021,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3170,8 +3090,6 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -3327,8 +3245,6 @@ concat(c1,'y') IN
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3407,8 +3323,6 @@ concat(c1,'y') IN
         "select#": 3,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3471,8 +3385,6 @@ concat(c1,'y') IN
         "select#": 2,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3560,10 +3472,6 @@ select * from t1,t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3693,11 +3601,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t3",
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3824,11 +3727,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t3",
-              "t1",
-              "t2"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -3939,8 +3837,6 @@ select * from t1 left join t2 on t2.a=50
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4098,8 +3994,6 @@ select * from t1 where (t1.a,t1.b) not i
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4183,8 +4077,6 @@ select * from t1 where (t1.a,t1.b) not i
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4289,8 +4181,6 @@ trace
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4622,8 +4512,6 @@ insert into t6 select * from t6 where d>
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4756,9 +4644,6 @@ update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -4904,9 +4789,6 @@ delete t6 from t5, t6 where d>7000	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-              "t5"
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5033,10 +4915,10 @@ select 5;
 5
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-select 3	{
+select 2	{
   "steps": [
     {
-      "expanded_query": "/* select#1 */ select 3 AS `3`"
+      "expanded_query": "/* select#1 */ select 2 AS `2`"
     },
     {
       "join_preparation": {
@@ -5044,20 +4926,13 @@ select 3	{
         "steps": [
         ] /* steps */
       } /* join_preparation */
-    },
-    {
-      "join_optimization": {
-        "select#": 1,
-        "steps": [
-        ] /* steps */
-      } /* join_optimization */
     }
   ] /* steps */
 }	0	0
-select 4	{
+select 2	{
   "steps": [
     {
-      "expanded_query": "/* select#1 */ select 4 AS `4`"
+      "expanded_query": "/* select#1 */ select 2 AS `2`"
     },
     {
       "join_preparation": {
@@ -5095,10 +4970,10 @@ select 5;
 5
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-select 4	{
+select 5	{
   "steps": [
     {
-      "expanded_query": "/* select#1 */ select 4 AS `4`"
+      "expanded_query": "/* select#1 */ select 5 AS `5`"
     },
     {
       "join_preparation": {
@@ -5106,13 +4981,6 @@ select 4	{
         "steps": [
         ] /* steps */
       } /* join_preparation */
-    },
-    {
-      "join_optimization": {
-        "select#": 1,
-        "steps": [
-        ] /* steps */
-      } /* join_optimization */
     }
   ] /* steps */
 }	0	0
@@ -5181,8 +5049,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5266,8 +5132,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5348,8 +5212,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5409,14 +5271,387 @@ select sum(data) into ret from t1	{
     }
   ] /* steps */
 }	0	0
-set optimizer_trace_offset=-4, optimizer_trace_limit=4|
+set optimizer_trace_offset=-7, optimizer_trace_limit=7|
 select @@optimizer_trace_offset, @@optimizer_trace_limit|
 @@optimizer_trace_offset	@@optimizer_trace_limit
--4	4
+-7	7
 select * from t6 where d in (select f1() from t2 where s="c")|
 d
 select * from information_schema.OPTIMIZER_TRACE|
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
+select * from t6 where d in (select f1() from t2 where s="c")	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d` from `test`.`t6` where `d` in (/* select#2 */ select `f1`() from `test`.`t2` where (`s` = 'c'))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "join_preparation": {
+              "select#": 2,
+              "steps": [
+                {
+                  "transformation": {
+                    "select#": 2,
+                    "from": "IN (SELECT)",
+                    "to": "semijoin",
+                    "chosen": true
+                  } /* transformation */
+                }
+              ] /* steps */
+            } /* join_preparation */
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "transformation": {
+              "select#": 2,
+              "from": "IN (SELECT)",
+              "to": "semijoin",
+              "chosen": true
+            } /* transformation */
+          },
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "(1 and (`test`.`t2`.`s` = 'c') and (`test`.`t6`.`d` = `f1`()))",
+              "after_equality_propagation": "(1 and multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))",
+              "after_constant_propagation": "(1 and multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))",
+              "after_trivial_conditions_removal": "(multiple equal('c', `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+            } /* condition_processing */
+          },
+          {
+            "ref-optimizer-key-uses": [
+              {
+                "condition": "t6.d= `f1`()",
+                "null_rejecting": false
+              }
+            ] /* ref-optimizer-key-uses */
+          },
+          {
+            "records_estimation": [
+              {
+                "database": "test",
+                "table": "t6",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "usable": true,
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_covering_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_covering_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_single_table"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "3 <= d <= 3"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */
+                } /* range_analysis */
+              },
+              {
+                "database": "test",
+                "table": "t2",
+                "table_scan": {
+                  "records": 3,
+                  "cost": 2
+                } /* table_scan */
+              }
+            ] /* records_estimation */
+          },
+          {
+            "pulled_out_semijoin_tables": [
+            ] /* pulled_out_semijoin_tables */
+          },
+          {
+            "execution_plan_for_potential_materialization": {
+              "steps": [
+                {
+                  "considered_execution_plans": [
+                    {
+                      "database": "test",
+                      "table": "t2",
+                      "best_access_path": {
+                        "considered_access_paths": [
+                          {
+                            "access_type": "scan",
+                            "using_join_cache": true,
+                            "records": 3,
+                            "cost": 2.0212,
+                            "chosen": true
+                          }
+                        ] /* considered_access_paths */
+                      } /* best_access_path */,
+                      "cost_for_plan": 2.0212,
+                      "records_for_plan": 3,
+                      "semijoin_strategy_choice": [
+                      ] /* semijoin_strategy_choice */,
+                      "chosen": true
+                    }
+                  ] /* considered_execution_plans */
+                }
+              ] /* steps */
+            } /* execution_plan_for_potential_materialization */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "database": "test",
+                "table": "t2",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_join_cache": true,
+                      "records": 3,
+                      "cost": 2.0212,
+                      "chosen": true
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.0212,
+                "records_for_plan": 3,
+                "semijoin_strategy_choice": [
+                ] /* semijoin_strategy_choice */,
+                "rest_of_plan": [
+                  {
+                    "database": "test",
+                    "table": "t6",
+                    "best_access_path": {
+                      "considered_access_paths": [
+                        {
+                          "access_type": "ref",
+                          "index": "d",
+                          "records": 1,
+                          "cost": 3,
+                          "chosen": true
+                        },
+                        {
+                          "access_type": "scan",
+                          "using_join_cache": true,
+                          "records": 1,
+                          "cost": 2.6076,
+                          "chosen": true
+                        }
+                      ] /* considered_access_paths */
+                    } /* best_access_path */,
+                    "cost_for_plan": 4.6289,
+                    "records_for_plan": 3,
+                    "semijoin_strategy_choice": [
+                      {
+                        "strategy": "DuplicatesWeedout",
+                        "cost": 5.2289,
+                        "records": 1,
+                        "duplicate_tables_left": true,
+                        "chosen": true
+                      }
+                    ] /* semijoin_strategy_choice */,
+                    "chosen": true
+                  }
+                ] /* rest_of_plan */
+              },
+              {
+                "database": "test",
+                "table": "t6",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "d",
+                      "records": 1,
+                      "cost": 1,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "scan",
+                      "cost": 2,
+                      "records": 4,
+                      "cause": "cost",
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 1,
+                "records_for_plan": 1,
+                "semijoin_strategy_choice": [
+                ] /* semijoin_strategy_choice */,
+                "rest_of_plan": [
+                  {
+                    "database": "test",
+                    "table": "t2",
+                    "best_access_path": {
+                      "considered_access_paths": [
+                        {
+                          "access_type": "scan",
+                          "using_join_cache": true,
+                          "records": 3,
+                          "cost": 2.0213,
+                          "chosen": true
+                        }
+                      ] /* considered_access_paths */
+                    } /* best_access_path */,
+                    "cost_for_plan": 3.0213,
+                    "records_for_plan": 3,
+                    "semijoin_strategy_choice": [
+                      {
+                        "strategy": "FirstMatch",
+                        "recompute_best_access_paths": {
+                          "cause": "join_buffering_not_possible",
+                          "tables": [
+                            {
+                              "database": "test",
+                              "table": "t2",
+                              "best_access_path": {
+                                "considered_access_paths": [
+                                  {
+                                    "access_type": "scan",
+                                    "using_join_cache": true,
+                                    "records": 3,
+                                    "cost": 2.0213,
+                                    "chosen": true
+                                  }
+                                ] /* considered_access_paths */
+                              } /* best_access_path */
+                            }
+                          ] /* tables */
+                        } /* recompute_best_access_paths */,
+                        "cost": 3.0213,
+                        "records": 1,
+                        "chosen": true
+                      },
+                      {
+                        "strategy": "MaterializationLookup",
+                        "cost": 3.2212,
+                        "records": 1,
+                        "duplicate_tables_left": false,
+                        "chosen": false
+                      },
+                      {
+                        "strategy": "DuplicatesWeedout",
+                        "cost": 3.6213,
+                        "records": 1,
+                        "duplicate_tables_left": false,
+                        "chosen": false
+                      }
+                    ] /* semijoin_strategy_choice */,
+                    "chosen": true
+                  }
+                ] /* rest_of_plan */
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "reconsidering_access_paths_for_semijoin": {
+              "strategy": "FirstMatch",
+              "database": "test",
+              "table": "t2",
+              "best_access_path": {
+                "considered_access_paths": [
+                  {
+                    "access_type": "scan",
+                    "records": 3,
+                    "cost": 2.0212,
+                    "chosen": true
+                  }
+                ] /* considered_access_paths */
+              } /* best_access_path */
+            } /* reconsidering_access_paths_for_semijoin */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))",
+              "attached_conditions": [
+                {
+                  "database": "test",
+                  "table": "t6",
+                  "attached": "(`test`.`t6`.`d` = `f1`())"
+                },
+                {
+                  "database": "test",
+                  "table": "t2",
+                  "attached": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))"
+                }
+              ] /* attached_conditions */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "database": "test",
+                "table": "t6"
+              },
+              {
+                "database": "test",
+                "table": "t2",
+                "scan_type": "table"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    }
+  ] /* steps */
+}	0	0
+insert into t1 values("z",0)	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select  from dual"
+    }
+  ] /* steps */
+}	0	0
+delete from t1 where id="z"	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
+    },
+    {
+      "database": "test",
+      "table": "t1",
+      "range_analysis": {
+        "table_scan": {
+          "records": 3,
+          "cost": 4.7154
+        } /* table_scan */
+      } /* range_analysis */
+    }
+  ] /* steps */
+}	0	0
 select sum(data) into ret from t1	{
   "steps": [
     {
@@ -5434,8 +5669,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5536,8 +5769,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5602,20 +5833,10 @@ select * from t6 where d in (select f1()
 d
 select * from information_schema.OPTIMIZER_TRACE|
 QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-delete from t1 where id="z"	{
+insert into t1 values("z",0)	{
   "steps": [
     {
-      "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
-    },
-    {
-      "database": "test",
-      "table": "t1",
-      "range_analysis": {
-        "table_scan": {
-          "records": 3,
-          "cost": 4.7154
-        } /* table_scan */
-      } /* range_analysis */
+      "expanded_query": "/* select#1 */ select  from dual"
     }
   ] /* steps */
 }	0	0
@@ -5665,8 +5886,6 @@ select d+1 into res from t6 where d= NAM
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5734,8 +5953,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5805,12 +6022,9 @@ c	3	3
 3	100	200
 3	100	200
 prepare stmt from 'call p1(?)';
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-prepare stmt from 'call p1(?)'	{
-  "steps": [
-  ] /* steps */
-}	0	0
+select QUERY from information_schema.OPTIMIZER_TRACE;
+QUERY
+select * from t2
 set @param="c";
 execute stmt using @param;
 Warnings:
@@ -5852,8 +6066,6 @@ select @trace;
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -5981,8 +6193,6 @@ select d into res from t6 where d in (se
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6281,8 +6491,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6383,8 +6591,6 @@ select sum(data) into ret from t1	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6444,10 +6650,6 @@ select sum(data) into ret from t1	{
     }
   ] /* steps */
 }	0	0
-SET optimizer_trace="enabled=off"	{
-  "steps": [
-  ] /* steps */
-}	0	0
 select @@optimizer_trace|
 @@optimizer_trace
 enabled=off,end_marker=on,one_line=off
@@ -6466,8 +6668,8 @@ explain select * from v1 where id="b"	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "merged": true
       } /* view */
@@ -6500,8 +6702,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6581,7 +6781,7 @@ delete from v1 where data=100	{
     },
     {
       "database": "test",
-      "table": "v1",
+      "table": "t1",
       "range_analysis": {
         "table_scan": {
           "records": 3,
@@ -6603,8 +6803,8 @@ explain select * from v1 where id="b"	{
   "steps": [
     {
       "view": {
-        "db": "test",
-        "name": "v1",
+        "database": "test",
+        "view": "v1",
         "in_select#": 1,
         "materialized": true
       } /* view */
@@ -6637,8 +6837,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -6721,8 +6919,6 @@ explain select * from v1 where id="b"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "",
@@ -6820,8 +7016,6 @@ VARIABLE_NAME="optimizer_trace"	{
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "information_schema",
@@ -6932,8 +7126,6 @@ select TRACE into dumpfile 'MYSQLTEST_VA
         "select#": "fake",
         "steps": [
           {
-            "constant_tables": [
-            ],
             "records_estimation": [
               {
                 "database": "",
@@ -6997,6 +7189,29 @@ ERROR 42000: Variable 'optimizer_switch'
 select @@optimizer_switch;
 @@optimizer_switch
 index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on,mrr=on,mrr_cost_based=off,index_condition_pushdown=on
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
+select "abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col	{
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select 'abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def' AS `col`"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    }
+  ]
+}	0	0
 drop table t1,t2;
 DROP TABLE t5,t6;
 set optimizer_trace=default;

=== modified file 'mysql-test/r/optimizer_trace_range.result'
--- a/mysql-test/r/optimizer_trace_range.result	2010-11-22 09:59:17 +0000
+++ b/mysql-test/r/optimizer_trace_range.result	2010-11-24 18:54:26 +0000
@@ -71,8 +71,6 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -253,8 +251,6 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -370,8 +366,6 @@ EXPLAIN SELECT * FROM t1 WHERE key1 < 3 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -576,8 +570,6 @@ EXPLAIN SELECT key2, MIN(key2_1) FROM t2
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -765,8 +757,6 @@ EXPLAIN SELECT DISTINCT key2 FROM t2	{
         "select#": 1,
         "steps": [
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -847,7 +837,7 @@ EXPLAIN SELECT DISTINCT key2 FROM t2	{
                   "best_group_range_summary": {
                     "type": "index_group",
                     "index": "i2_1",
-                    "group_attribute": "null",
+                    "group_attribute": null,
                     "min_aggregate": false,
                     "max_aggregate": false,
                     "distinct_aggregate": false,
@@ -864,7 +854,7 @@ EXPLAIN SELECT DISTINCT key2 FROM t2	{
                     "range_access_plan": {
                       "type": "index_group",
                       "index": "i2_1",
-                      "group_attribute": "null",
+                      "group_attribute": null,
                       "min_aggregate": false,
                       "max_aggregate": false,
                       "distinct_aggregate": false,
@@ -968,8 +958,6 @@ EXPLAIN SELECT key2, MIN(key2_1) FROM t2
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1203,8 +1191,6 @@ EXPLAIN SELECT * FROM t2 WHERE key2 = 1 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1390,8 +1376,6 @@ EXPLAIN SELECT * FROM t1 WHERE key2=10 O
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1644,8 +1628,6 @@ EXPLAIN SELECT * FROM t2 WHERE key2_1 < 
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1782,8 +1764,6 @@ EXPLAIN SELECT * FROM t2 WHERE key1a = 5
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -1964,8 +1944,6 @@ EXPLAIN SELECT * FROM t1 WHERE (key1 > 1
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2177,8 +2155,6 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2397,8 +2373,6 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
             ] /* ref-optimizer-key-uses */
           },
           {
-            "constant_tables": [
-            ] /* constant_tables */,
             "records_estimation": [
               {
                 "database": "test",
@@ -2431,9 +2405,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
                       {
                         "index": "cola",
                         "ranges": [
-                          "f
-o <= cola <= f
-o"
+                          "f\no <= cola <= f\no"
                         ] /* ranges */,
                         "index_only": false,
                         "records": 1,
@@ -2453,9 +2425,7 @@ o"
                       "index": "cola",
                       "records": 1,
                       "ranges": [
-                        "f
-o <= cola <= f
-o"
+                        "f\no <= cola <= f\no"
                       ] /* ranges */
                     } /* range_access_plan */,
                     "records_for_plan": 1,

=== removed file 'mysql-test/suite/ndb/r/optimizer_trace_range_opt_bug.result'
--- a/mysql-test/suite/ndb/r/optimizer_trace_range_opt_bug.result	2010-05-25 09:49:19 +0000
+++ b/mysql-test/suite/ndb/r/optimizer_trace_range_opt_bug.result	1970-01-01 00:00:00 +0000
@@ -1,1031 +0,0 @@
-create table t1 (
-uid int, fid int, index(uid)
-) engine=ndb;
-insert into t1 values
-(1,1), (1,2), (1,3), (1,4),
-(2,5), (2,6), (2,7), (2,8),
-(3,1), (3,2), (3,9);
-create table t2 (
-uid int primary key, name varchar(128), index(name)
-) engine=ndb;
-insert into t2 values 
-(1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"),
-(6, "F"), (7, "G"), (8, "H"), (9, "I");
-create table t3 (
-uid int, fid int, index(uid)
-) engine=ndb;
-insert into t3 values
-(1,1), (1,2), (1,3),(1,4),
-(2,5), (2,6), (2,7), (2,8),
-(3,1), (3,2), (3,9);
-create table t4 (
-uid int primary key, name varchar(128), index(name)
-) engine=ndb;
-insert into t4 values 
-(1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"),
-(6, "F"), (7, "G"), (8, "H"), (9, "I");
-select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid;
-uid
-1
-4
-2
-3
-set optimizer_join_cache_level=7;
-set optimizer_trace="enabled=on,end_marker=on";
-explain select name from t2, t1 
-where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid)
-and t2.uid=t1.fid;
-id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
-1	PRIMARY	t3	ref	uid	uid	5	const	10	Using where with pushed condition; Start temporary
-1	PRIMARY	t4	eq_ref	PRIMARY	PRIMARY	4	test.t3.fid	1	
-1	PRIMARY	t1	ref	uid	uid	5	test.t4.uid	1	Using where with pushed condition; End temporary
-1	PRIMARY	t2	eq_ref	PRIMARY	PRIMARY	4	test.t1.fid	1	
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY_ID	TRACE
-0	
-{
-  "top_query": "explain select name from t2, t1 
-where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid)
-and t2.uid=t1.fid",
-  "join_preparation": {
-    "join_preparation": {
-      "subquery_strategy": {
-        "subquery": "`t1`.`uid` in (select #2)",
-        "maybe_semijoin_transformation": true
-      } /* subquery_strategy */
-    } /* join_preparation */
-  } /* join_preparation */,
-  "join_optimization": {
-    "transformation": {
-      "from": "subquery",
-      "to": "semijoin",
-      "transformed": [
-        "`test`.`t1`.`uid` in (select #2)"
-      ] /* transformed */
-    } /* transformation */,
-    "condition_processing": {
-      "condition": "WHERE",
-      "original_condition": "(1 and (`test`.`t2`.`uid` = `test`.`t1`.`fid`) and (`test`.`t3`.`uid` = 1) and (`test`.`t4`.`uid` = `test`.`t3`.`fid`) and (`test`.`t1`.`uid` = `test`.`t4`.`uid`))",
-      "after_equality_propagation": "(1 and multiple equal(`test`.`t2`.`uid`, `test`.`t1`.`fid`) and multiple equal(1, `test`.`t3`.`uid`) and multiple equal(`test`.`t4`.`uid`, `test`.`t3`.`fid`, `test`.`t1`.`uid`))",
-      "after_constant_propagation": "(1 and multiple equal(`test`.`t2`.`uid`, `test`.`t1`.`fid`) and multiple equal(1, `test`.`t3`.`uid`) and multiple equal(`test`.`t4`.`uid`, `test`.`t3`.`fid`, `test`.`t1`.`uid`))",
-      "after_trivial_conditions_removal": "(multiple equal(`test`.`t2`.`uid`, `test`.`t1`.`fid`) and multiple equal(1, `test`.`t3`.`uid`) and multiple equal(`test`.`t4`.`uid`, `test`.`t3`.`fid`, `test`.`t1`.`uid`))"
-    } /* condition_processing */,
-    "ref-optimizer": {
-      "keyuse": {
-        "condition": "t2.uid= `test`.`t1`.`fid`",
-        "null_rejecting": true
-      } /* keyuse */,
-      "keyuse": {
-        "condition": "t1.uid= `test`.`t4`.`uid`",
-        "null_rejecting": false
-      } /* keyuse */,
-      "keyuse": {
-        "condition": "t1.uid= `test`.`t3`.`fid`",
-        "null_rejecting": true
-      } /* keyuse */,
-      "keyuse": {
-        "condition": "t4.uid= `test`.`t3`.`fid`",
-        "null_rejecting": true
-      } /* keyuse */,
-      "keyuse": {
-        "condition": "t4.uid= `test`.`t1`.`uid`",
-        "null_rejecting": true
-      } /* keyuse */,
-      "keyuse": {
-        "condition": "t3.uid= 1",
-        "null_rejecting": false
-      } /* keyuse */
-    } /* ref-optimizer */,
-    "constant_table_detection": {
-      "records_estimation": [
-        {
-          "table": "t2",
-          "table_scan": {
-            "records": 9,
-            "cost": 9000
-          } /* table_scan */
-        },
-        {
-          "table": "t1",
-          "table_scan": {
-            "records": 11,
-            "cost": 11000
-          } /* table_scan */
-        },
-        {
-          "table": "t4",
-          "table_scan": {
-            "records": 9,
-            "cost": 9000
-          } /* table_scan */
-        },
-        {
-          "table": "t3",
-          "more_range_optimizer_trace": {
-            "TODO?": "yes!"
-          } /* more_range_optimizer_trace */
-        }
-      ] /* records_estimation */
-    } /* constant_table_detection */,
-    "semijoin_table_pullout": {
-      "pulled_out": {
-        "table": "t4",
-        "functionally_dependent": true
-      } /* pulled_out */
-    } /* semijoin_table_pullout */,
-    "execution_plan_for_potential_materialization": {
-    } /* execution_plan_for_potential_materialization */,
-    "considered_execution_plans": [
-      {
-        "table": "t2",
-        "best_access_path": {
-          "considered_access_paths": [
-            {
-              "access_type": "index",
-              "index": "PRIMARY",
-              "usable": false,
-              "chosen": false
-            },
-            {
-              "access_type": "table scan",
-              "cost": 9000,
-              "records": 9,
-              "chosen": true
-            }
-          ] /* considered_access_paths */
-        } /* best_access_path */,
-        "cost_for_plan": 9000,
-        "records_for_plan": 9,
-        "semijoin_strategy_choice": [
-        ] /* semijoin_strategy_choice */,
-        "rest_of_plan": [
-          {
-            "table": "t4",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "PRIMARY",
-                  "usable": false,
-                  "chosen": false
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 9082.8,
-                  "records": 9,
-                  "chosen": true
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 18083,
-            "records_for_plan": 81,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "rest_of_plan": [
-              {
-                "table": "t3",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 162,
-                      "records": 10,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "heuristic_index_must_be_cheaper": true,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 18245,
-                "records_for_plan": 810,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t1",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "uid",
-                          "cost": 810,
-                          "records": 1,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "cost": 11000,
-                          "records": 11,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 19055,
-                    "records_for_plan": 810,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 19500,
-                        "records": 81,
-                        "duplicate_tables_left": true,
-                        "chosen": true
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              },
-              {
-                "table": "t1",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 81,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 11000,
-                      "records": 11,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 18164,
-                "records_for_plan": 81,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t3",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "uid",
-                          "cost": 162,
-                          "records": 10,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "heuristic_index_must_be_cheaper": true,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 18326,
-                    "records_for_plan": 810,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "FirstMatch",
-                        "cost": 18326,
-                        "records": 81,
-                        "chosen": true
-                      },
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 18771,
-                        "records": 81,
-                        "duplicate_tables_left": false,
-                        "chosen": false
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              }
-            ] /* rest_of_plan */
-          },
-          {
-            "table": "t3",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "uid",
-                  "cost": 18,
-                  "records": 10,
-                  "chosen": true
-                },
-                {
-                  "access_type": "table scan",
-                  "heuristic_index_must_be_cheaper": true,
-                  "chosen": false
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 9018,
-            "records_for_plan": 90,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "rest_of_plan": [
-              {
-                "table": "t4",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "PRIMARY",
-                      "cost": 10,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 9000,
-                      "records": 9,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9028,
-                "records_for_plan": 90,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t1",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "uid",
-                          "cost": 90,
-                          "records": 1,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "cost": 11000,
-                          "records": 11,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 9118,
-                    "records_for_plan": 90,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 9167.5,
-                        "records": 9,
-                        "duplicate_tables_left": true,
-                        "chosen": true
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              },
-              {
-                "table": "t1",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 90,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 11000,
-                      "records": 11,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9108,
-                "records_for_plan": 90,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "pruned_by_heuristic": true
-              }
-            ] /* rest_of_plan */
-          },
-          {
-            "table": "t1",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "uid",
-                  "usable": false,
-                  "chosen": false
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 11101,
-                  "records": 11,
-                  "chosen": true
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 20101,
-            "records_for_plan": 99,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "pruned_by_cost": true
-          }
-        ] /* rest_of_plan */
-      },
-      {
-        "table": "t4",
-        "best_access_path": {
-          "considered_access_paths": [
-            {
-              "access_type": "index",
-              "index": "PRIMARY",
-              "usable": false,
-              "chosen": false
-            },
-            {
-              "access_type": "table scan",
-              "cost": 9000,
-              "records": 9,
-              "chosen": true
-            }
-          ] /* considered_access_paths */
-        } /* best_access_path */,
-        "cost_for_plan": 9000,
-        "records_for_plan": 9,
-        "semijoin_strategy_choice": [
-        ] /* semijoin_strategy_choice */,
-        "rest_of_plan": [
-          {
-            "table": "t2",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "PRIMARY",
-                  "usable": false,
-                  "chosen": false
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 9002.5,
-                  "records": 9,
-                  "chosen": true
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 18002,
-            "records_for_plan": 81,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "pruned_by_cost": true
-          },
-          {
-            "table": "t3",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "uid",
-                  "cost": 18,
-                  "records": 10,
-                  "chosen": true
-                },
-                {
-                  "access_type": "table scan",
-                  "heuristic_index_must_be_cheaper": true,
-                  "chosen": false
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 9018,
-            "records_for_plan": 90,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "rest_of_plan": [
-              {
-                "table": "t2",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "PRIMARY",
-                      "usable": false,
-                      "chosen": false
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 9080.3,
-                      "records": 9,
-                      "chosen": true
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 18098,
-                "records_for_plan": 810,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "pruned_by_cost": true
-              },
-              {
-                "table": "t1",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 90,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 11000,
-                      "records": 11,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9108,
-                "records_for_plan": 90,
-                "semijoin_strategy_choice": [
-                  {
-                    "strategy": "DuplicatesWeedout",
-                    "cost": 9157.5,
-                    "records": 9,
-                    "duplicate_tables_left": true,
-                    "chosen": true
-                  }
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t2",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "PRIMARY",
-                          "cost": 9,
-                          "records": 1,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "cost": 9000,
-                          "records": 9,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 9166.5,
-                    "records_for_plan": 9,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 9166.5,
-                        "records": 9,
-                        "duplicate_tables_left": false,
-                        "chosen": false
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              }
-            ] /* rest_of_plan */
-          },
-          {
-            "table": "t1",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "uid",
-                  "cost": 9,
-                  "records": 1,
-                  "chosen": true
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 11000,
-                  "records": 11,
-                  "chosen": false
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 9009,
-            "records_for_plan": 9,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "rest_of_plan": [
-              {
-                "table": "t3",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 18,
-                      "records": 10,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "heuristic_index_must_be_cheaper": true,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9027,
-                "records_for_plan": 90,
-                "semijoin_strategy_choice": [
-                  {
-                    "strategy": "FirstMatch",
-                    "cost": 9027,
-                    "records": 9,
-                    "chosen": true
-                  },
-                  {
-                    "strategy": "DuplicatesWeedout",
-                    "cost": 9076.5,
-                    "records": 9,
-                    "duplicate_tables_left": false,
-                    "chosen": false
-                  }
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t2",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "PRIMARY",
-                          "cost": 9,
-                          "records": 1,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "cost": 9000,
-                          "records": 9,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 9036,
-                    "records_for_plan": 9,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 9085.5,
-                        "records": 9,
-                        "duplicate_tables_left": false,
-                        "chosen": false
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              },
-              {
-                "table": "t2",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "PRIMARY",
-                      "cost": 9,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 9000,
-                      "records": 9,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9018,
-                "records_for_plan": 9,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t3",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "uid",
-                          "cost": 18,
-                          "records": 10,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "heuristic_index_must_be_cheaper": true,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 9036,
-                    "records_for_plan": 90,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "FirstMatch",
-                        "cost": 9036,
-                        "records": 9,
-                        "chosen": true
-                      },
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 9085.5,
-                        "records": 9,
-                        "duplicate_tables_left": false,
-                        "chosen": false
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "pruned_by_cost": true
-                  }
-                ] /* rest_of_plan */
-              }
-            ] /* rest_of_plan */
-          }
-        ] /* rest_of_plan */
-      },
-      {
-        "table": "t3",
-        "best_access_path": {
-          "considered_access_paths": [
-            {
-              "access_type": "index",
-              "index": "uid",
-              "cost": 2,
-              "records": 10,
-              "chosen": true
-            },
-            {
-              "access_type": "table scan",
-              "heuristic_index_must_be_cheaper": true,
-              "chosen": false
-            }
-          ] /* considered_access_paths */
-        } /* best_access_path */,
-        "cost_for_plan": 2,
-        "records_for_plan": 10,
-        "semijoin_strategy_choice": [
-        ] /* semijoin_strategy_choice */,
-        "rest_of_plan": [
-          {
-            "table": "t4",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "PRIMARY",
-                  "cost": 10,
-                  "records": 1,
-                  "chosen": true
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 9000,
-                  "records": 9,
-                  "chosen": false
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 12,
-            "records_for_plan": 10,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "rest_of_plan": [
-              {
-                "table": "t2",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "PRIMARY",
-                      "usable": false,
-                      "chosen": false
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 9008.9,
-                      "records": 9,
-                      "chosen": true
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 9020.9,
-                "records_for_plan": 90,
-                "semijoin_strategy_choice": [
-                ] /* semijoin_strategy_choice */,
-                "pruned_by_cost": true
-              },
-              {
-                "table": "t1",
-                "best_access_path": {
-                  "considered_access_paths": [
-                    {
-                      "access_type": "index",
-                      "index": "uid",
-                      "cost": 10,
-                      "records": 1,
-                      "chosen": true
-                    },
-                    {
-                      "access_type": "table scan",
-                      "cost": 11000,
-                      "records": 11,
-                      "chosen": false
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 22,
-                "records_for_plan": 10,
-                "semijoin_strategy_choice": [
-                  {
-                    "strategy": "DuplicatesWeedout",
-                    "cost": 27.5,
-                    "records": 1,
-                    "duplicate_tables_left": true,
-                    "chosen": true
-                  }
-                ] /* semijoin_strategy_choice */,
-                "rest_of_plan": [
-                  {
-                    "table": "t2",
-                    "best_access_path": {
-                      "considered_access_paths": [
-                        {
-                          "access_type": "index",
-                          "index": "PRIMARY",
-                          "cost": 10,
-                          "records": 1,
-                          "chosen": true
-                        },
-                        {
-                          "access_type": "table scan",
-                          "cost": 9000,
-                          "records": 9,
-                          "chosen": false
-                        }
-                      ] /* considered_access_paths */
-                    } /* best_access_path */,
-                    "cost_for_plan": 37.5,
-                    "records_for_plan": 1,
-                    "semijoin_strategy_choice": [
-                      {
-                        "strategy": "DuplicatesWeedout",
-                        "cost": 37.5,
-                        "records": 1,
-                        "duplicate_tables_left": false,
-                        "chosen": false
-                      }
-                    ] /* semijoin_strategy_choice */,
-                    "chosen": true
-                  }
-                ] /* rest_of_plan */
-              }
-            ] /* rest_of_plan */
-          },
-          {
-            "table": "t2",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "PRIMARY",
-                  "usable": false,
-                  "chosen": false
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 9006.2,
-                  "records": 9,
-                  "chosen": true
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 9008.2,
-            "records_for_plan": 90,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "pruned_by_cost": true
-          },
-          {
-            "table": "t1",
-            "best_access_path": {
-              "considered_access_paths": [
-                {
-                  "access_type": "index",
-                  "index": "uid",
-                  "cost": 10,
-                  "records": 1,
-                  "chosen": true
-                },
-                {
-                  "access_type": "table scan",
-                  "cost": 11000,
-                  "records": 11,
-                  "chosen": false
-                }
-              ] /* considered_access_paths */
-            } /* best_access_path */,
-            "cost_for_plan": 12,
-            "records_for_plan": 10,
-            "semijoin_strategy_choice": [
-            ] /* semijoin_strategy_choice */,
-            "pruned_by_heuristic": true
-          }
-        ] /* rest_of_plan */
-      },
-      {
-        "table": "t1",
-        "best_access_path": {
-          "considered_access_paths": [
-            {
-              "access_type": "index",
-              "index": "uid",
-              "usable": false,
-              "chosen": false
-            },
-            {
-              "access_type": "table scan",
-              "cost": 11000,
-              "records": 11,
-              "chosen": true
-            }
-          ] /* considered_access_paths */
-        } /* best_access_path */,
-        "cost_for_plan": 11000,
-        "records_for_plan": 11,
-        "semijoin_strategy_choice": [
-        ] /* semijoin_strategy_choice */,
-        "pruned_by_cost": true
-      }
-    ] /* considered_execution_plans */,
-    "attaching_conditions_to_tables": {
-      "original_condition": "((`test`.`t4`.`uid` = `test`.`t3`.`fid`) and (`test`.`t1`.`uid` = `test`.`t3`.`fid`) and (`test`.`t3`.`uid` = 1) and (`test`.`t2`.`uid` = `test`.`t1`.`fid`))",
-      "attached_conditions": [
-        {
-          "table": "t3",
-          "attached": "(`test`.`t3`.`fid` is not null)"
-        },
-        {
-          "table": "t4",
-          "attached": "<null>"
-        },
-        {
-          "table": "t1",
-          "attached": "((`test`.`t1`.`uid` = `test`.`t3`.`fid`) and (`test`.`t1`.`fid` is not null))"
-        },
-        {
-          "table": "t2",
-          "attached": "<null>"
-        }
-      ] /* attached_conditions */
-    } /* attaching_conditions_to_tables */
-  } /* join_optimization */
-}
-select name from t2, t1 
-where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid)
-and t2.uid=t1.fid;
-name
-A
-A
-B
-B
-C
-D
-E
-F
-G
-H
-I
-select name from t2, t1 
-where t1.uid in (1,3,2,3,4)
-and t2.uid=t1.fid;
-name
-A
-A
-B
-B
-C
-D
-E
-F
-G
-H
-I
-set optimizer_join_cache_level=default;
-drop table t1,t2,t3,t4;

=== removed file 'mysql-test/suite/ndb/t/optimizer_trace_range_opt_bug.test'
--- a/mysql-test/suite/ndb/t/optimizer_trace_range_opt_bug.test	2010-05-25 09:49:19 +0000
+++ b/mysql-test/suite/ndb/t/optimizer_trace_range_opt_bug.test	1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
--- source include/have_ndb.inc
--- source include/not_embedded.inc
-
-# this comes from test for BUG#53305
-
-create table t1 (
-  uid int, fid int, index(uid)
-) engine=ndb;
-insert into t1 values
-  (1,1), (1,2), (1,3), (1,4),
-  (2,5), (2,6), (2,7), (2,8),
-  (3,1), (3,2), (3,9);
-
-create table t2 (
-  uid int primary key, name varchar(128), index(name)
-) engine=ndb;
-insert into t2 values 
-  (1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"),
-  (6, "F"), (7, "G"), (8, "H"), (9, "I");
-
-create table t3 (
-  uid int, fid int, index(uid)
-) engine=ndb;
-insert into t3 values
-  (1,1), (1,2), (1,3),(1,4),
-  (2,5), (2,6), (2,7), (2,8),
-  (3,1), (3,2), (3,9);
-
-create table t4 (
-  uid int primary key, name varchar(128), index(name)
-) engine=ndb;
-insert into t4 values 
-  (1, "A"), (2, "B"), (3, "C"), (4, "D"), (5, "E"),
-  (6, "F"), (7, "G"), (8, "H"), (9, "I");
-
-select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid;
-
-set optimizer_join_cache_level=7;
-
-set optimizer_trace="enabled=on,end_marker=on";
-explain select name from t2, t1 
-  where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid)
-        and t2.uid=t1.fid;
-select * from information_schema.OPTIMIZER_TRACE;
-
---sorted_result
-select name from t2, t1 
-  where t1.uid in (select t4.uid from t4, t3 where t3.uid=1 and t4.uid=t3.fid)
-        and t2.uid=t1.fid;
-
---sorted_result
-select name from t2, t1 
-  where t1.uid in (1,3,2,3,4)
-        and t2.uid=t1.fid;
-
-set optimizer_join_cache_level=default;
-
-drop table t1,t2,t3,t4;

=== modified file 'mysql-test/suite/sys_vars/r/optimizer_trace_features_basic.result'
--- a/mysql-test/suite/sys_vars/r/optimizer_trace_features_basic.result	2010-11-17 12:27:39 +0000
+++ b/mysql-test/suite/sys_vars/r/optimizer_trace_features_basic.result	2010-11-23 10:21:53 +0000
@@ -1,45 +1,45 @@
 SET @start_global_value = @@global.optimizer_trace_features;
 SELECT @start_global_value;
 @start_global_value
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on
 select @@global.optimizer_trace_features;
 @@global.optimizer_trace_features
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on
 select @@session.optimizer_trace_features;
 @@session.optimizer_trace_features
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on
 show global variables like 'optimizer_trace_features';
 Variable_name	Value
-optimizer_trace_features	misc=on,greedy_search=on,range_optimizer=on
+optimizer_trace_features	greedy_search=on,range_optimizer=on
 show session variables like 'optimizer_trace_features';
 Variable_name	Value
-optimizer_trace_features	misc=on,greedy_search=on,range_optimizer=on
+optimizer_trace_features	greedy_search=on,range_optimizer=on
 select * from information_schema.global_variables where variable_name='optimizer_trace_features';
 VARIABLE_NAME	VARIABLE_VALUE
-OPTIMIZER_TRACE_FEATURES	misc=on,greedy_search=on,range_optimizer=on
+OPTIMIZER_TRACE_FEATURES	greedy_search=on,range_optimizer=on
 select * from information_schema.session_variables where variable_name='optimizer_trace_features';
 VARIABLE_NAME	VARIABLE_VALUE
-OPTIMIZER_TRACE_FEATURES	misc=on,greedy_search=on,range_optimizer=on
+OPTIMIZER_TRACE_FEATURES	greedy_search=on,range_optimizer=on
 set global optimizer_trace_features=2;
 select @@global.optimizer_trace_features;
 @@global.optimizer_trace_features
-misc=off,greedy_search=on,range_optimizer=off
+greedy_search=off,range_optimizer=on
 set session optimizer_trace_features=2;
 select @@session.optimizer_trace_features;
 @@session.optimizer_trace_features
-misc=off,greedy_search=on,range_optimizer=off
+greedy_search=off,range_optimizer=on
 set global optimizer_trace_features=0;
 select @@global.optimizer_trace_features;
 @@global.optimizer_trace_features
-misc=off,greedy_search=off,range_optimizer=off
+greedy_search=off,range_optimizer=off
 set session optimizer_trace_features=0;
 select @@session.optimizer_trace_features;
 @@session.optimizer_trace_features
-misc=off,greedy_search=off,range_optimizer=off
+greedy_search=off,range_optimizer=off
 set session optimizer_trace_features=default;
 select @@session.optimizer_trace_features;
 @@session.optimizer_trace_features
-misc=off,greedy_search=off,range_optimizer=off
+greedy_search=off,range_optimizer=off
 set global optimizer_trace_features=1.1;
 ERROR 42000: Incorrect argument type to variable 'optimizer_trace_features'
 set global optimizer_trace_features=1e1;
@@ -49,4 +49,4 @@ ERROR 42000: Variable 'optimizer_trace_f
 SET @@global.optimizer_trace_features = @start_global_value;
 SELECT @@global.optimizer_trace_features;
 @@global.optimizer_trace_features
-misc=on,greedy_search=on,range_optimizer=on
+greedy_search=on,range_optimizer=on

=== added file 'mysql-test/t/optimizer_trace2.test'
--- a/mysql-test/t/optimizer_trace2.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_trace2.test	2010-12-19 14:24:03 +0000
@@ -0,0 +1,49 @@
+# Continuation of tests for optimizer trace
+
+--source include/have_optimizer_trace.inc
+
+set optimizer_trace="enabled=on,end_marker=on";
+
+# check that if a sub-statement should not be traced,
+# it is not traced even if inside a traced top statement
+
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+delimiter |;
+create function f1(arg char(1)) returns int
+begin
+  declare res int;
+  declare dummy varchar(1);
+  select 1 into res from dual;
+  select TRACE+NULL into dummy from information_schema.OPTIMIZER_TRACE limit 1;
+  select 2 into res from dual;
+  return 3;
+end|
+select f1("c")|
+--echo
+# we should not see the trace of "select TRACE+NULL..."
+# because tracing is disabled when OPTIMIZER_TRACE table is used.
+# "distinct" is because in ps-protocol mode, we get 'select f1("c")'
+# twice (one PREPARE, one EXECUTE), and we must have a single result
+# file for normal and ps-protocol mode.
+select distinct QUERY from information_schema.OPTIMIZER_TRACE|
+delimiter ;|
+set optimizer_trace_offset=default, optimizer_trace_limit=default;
+drop function f1;
+
+# check of crash with I_S.VIEWS (TABLE_LIST::alias==NULL)
+create table t1(a int, b int);
+create view v1 as select a from t1;
+select VIEW_DEFINITION from information_schema.VIEWS
+where TABLE_SCHEMA="test" and TABLE_NAME="v1";
+select locate("\"view\": \"v1\"", TRACE) != 0
+from information_schema.OPTIMIZER_TRACE;
+drop table t1;
+drop view v1;
+
+# check for readable display of BIT values
+create table t1 (a bit(5), key(a));
+insert into t1 values(b'00000'),(b'01101');
+select cast(a as unsigned) from t1 where a > b'01100';
+# Note that in the trace we get either 0x0c or 12
+select TRACE from information_schema.OPTIMIZER_TRACE;
+drop table t1;

=== modified file 'mysql-test/t/optimizer_trace_charset.test'
--- a/mysql-test/t/optimizer_trace_charset.test	2010-10-22 08:31:43 +0000
+++ b/mysql-test/t/optimizer_trace_charset.test	2010-11-24 18:54:26 +0000
@@ -13,6 +13,9 @@ if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL 
 set @@session.optimizer_trace="enabled=on,end_marker=on";
 create table t1(a int);
 insert into t1 values(1);
+
+# test non-utf8 chars in the SELECT list
+
 set names latin1;
 explain extended select '��� from t1 limit 1;
 # In the trace and EXPLAIN EXTENDED's warning we see symptoms of BUG#57341
@@ -24,19 +27,48 @@ select @query, @trace;
 set names utf8;
 select @query, @trace;
 
+# test non-utf8 chars in a view's definition
+
 set names latin1;
 create view v1 as select '��� as col from t1 limit 1;
 select * from v1 where v1.col = '���;
 select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
+set names utf8;
 select @query, @trace;
 
 drop table t1;
 drop view v1;
 
+# test non-ASCII chars in a range
+
+set names latin1;
 create table t1(c char(4) primary key);
 insert into t1 values ('aaa'), ('��');
 select * from t1 where c < '���;
-select query, trace from information_schema.OPTIMIZER_TRACE;
+select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
+set names utf8;
+select @query, @trace;
 drop table t1;
 
+# test non-ASCII chars in an identifier
+create table `t
+1	a`(`col
+1	a` int, index `index
+1	a` (`col
+1	a`));
+insert into `t
+1	a` values(2),(3);
+create view `v
+1	a` as select * from `t
+1	a`;
+select `col
+1	a` from `v
+1	a` where `col
+1	a` < 6;
+select query, trace from information_schema.OPTIMIZER_TRACE;
+drop table `t
+1	a`;
+drop view `v
+1	a`;
+
 set optimizer_trace=default;

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2010-11-22 13:22:03 +0000
+++ b/sql/opt_range.cc	2010-12-21 07:34:33 +0000
@@ -118,10 +118,6 @@
 #include <m_ctype.h>
 #include "sql_select.h"
 #include "opt_trace.h"
-/**
-   All tracing done is here is still SergeyP's prototype and not understood.
-   @todo fix this before release
-*/
 
 #ifndef EXTRA_DEBUG
 #define test_rb_tree(A,B) {}
@@ -796,17 +792,13 @@ TABLE_READ_PLAN *get_best_disjunct_quick
 static
 TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree,
                                           double read_time);
-#ifndef DBUG_OFF
+#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
 static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map,
                            const char *msg);
 static void print_ror_scans_arr(TABLE *table, const char *msg,
                                 struct st_ror_scan_info **start,
                                 struct st_ror_scan_info **end);
-#endif
-#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
-#if 0
 static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
-#endif
 static void append_range(String *out,
                          const KEY_PART_INFO *key_parts,
                          const uchar *min_key, const uchar *max_key,
@@ -1967,53 +1959,6 @@ public:
                                 Opt_trace_object *trace_object) const = 0;
 };
 
-/**
-  Print a key into a stream
-
-  @param[out] out          String the key is appended to
-  @param[in]  key_part     Index components description
-  @param[in]  key          Key tuple
-  @param[in]  used_length  Key tuple length
-*/
-static void
-print_key_value(String *out, const KEY_PART_INFO *key_part, const uchar *key)
-{
-  String tmp;
-  uint store_length;
-  TABLE *table= key_part->field->table;
-  my_bitmap_map *old_sets[2];
-
-  dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
-
-  Field *field= key_part->field;
-  store_length= key_part->store_length;
-
-  if (field->real_maybe_null())
-  {
-    /*
-      Byte 0 of key is the null-byte. If set, key is NULL.
-      Otherwise, print the key value starting immediately after the
-      null-byte
-    */
-    if (*key)
-    {
-      out->append(STRING_WITH_LEN("NULL"));
-      goto restore_col_map;
-    }
-    key++;                                    // Skip null byte
-    store_length--;
-  }
-  field->set_key_image(key, key_part->length);
-  if (field->type() == MYSQL_TYPE_BIT)
-    (void) field->val_int_as_str(&tmp, 1); // may change tmp's charset
-  else
-    field->val_str(&tmp); // may change tmp's charset
-  out->append(tmp.ptr(), tmp.length(), tmp.charset());
-
-restore_col_map:
-  dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
-}
-
 /*
   Plan for a QUICK_RANGE_SELECT scan.
   TRP_RANGE::make_quick ignores retrieve_full_rows parameter because
@@ -2058,9 +2003,8 @@ public:
     const KEY cur_key= param->table->key_info[keynr_in_table];
     const KEY_PART_INFO *key_part= cur_key.key_part;
 
-    trace_object->add_str("type", "range_scan").
-      add_str("index", cur_key.name, strlen(cur_key.name)).
-      add("records", records);
+    trace_object->add_alnum("type", "range_scan").
+      add_utf8("index", cur_key.name).add("records", records);
 
     Opt_trace_array trace_range(param->thd->opt_trace, "ranges");
     for (const SEL_ARG *current= key;
@@ -2078,7 +2022,7 @@ public:
                      part->min_value, part->max_value,
                      part->min_flag | part->max_flag);
       }
-      trace_range.add_str(range_info.ptr(), range_info.length());
+      trace_range.add_utf8(range_info.ptr(), range_info.length());
     }
 #endif
   }
@@ -2128,7 +2072,7 @@ public:
                         Opt_trace_object *trace_object) const
   {
 #ifdef OPTIMIZER_TRACE
-    trace_object->add_str("type", "index_roworder_intersect").
+    trace_object->add_alnum("type", "index_roworder_intersect").
       add("records", records).
       add("cost", read_cost).
       add("covering", is_covering).
@@ -2144,9 +2088,8 @@ public:
       const KEY_PART_INFO *key_part= cur_key.key_part;
 
       Opt_trace_object trace_isect_idx(trace_ctx);
-      trace_isect_idx.add_str("type", "range_scan").
-        add_str("index", cur_key.name, strlen(cur_key.name)).
-        add("records", (*cur_scan)->records);
+      trace_isect_idx.add_alnum("type", "range_scan").
+        add_utf8("index", cur_key.name).add("records", (*cur_scan)->records);
 
       Opt_trace_array trace_range(trace_ctx, "ranges");
       for (const SEL_ARG *current= (*cur_scan)->sel_arg;
@@ -2164,7 +2107,7 @@ public:
                        part->min_value, part->max_value,
                        part->min_flag | part->max_flag);
         }
-        trace_range.add_str(range_info.ptr(), range_info.length());
+        trace_range.add_utf8(range_info.ptr(), range_info.length());
       }
     }
 #endif
@@ -2192,7 +2135,7 @@ public:
                         Opt_trace_object *trace_object) const
   {
 #ifdef OPTIMIZER_TRACE
-    trace_object->add_str("type", "index_roworder_union");
+    trace_object->add_alnum("type", "index_roworder_union");
     Opt_trace_array ota(param->thd->opt_trace, "union_of");
     for (TABLE_READ_PLAN **current= first_ror;
          current != last_ror;
@@ -2225,7 +2168,7 @@ public:
                         Opt_trace_object *trace_object) const
   {
 #ifdef OPTIMIZER_TRACE
-    trace_object->add_str("type", "index_merge");
+    trace_object->add_alnum("type", "index_merge");
     Opt_trace_array ota(param->thd->opt_trace, "index_merge_of");
     for (TRP_RANGE **current= range_scans;
          current != range_scans_end;
@@ -2279,14 +2222,13 @@ public:
                         Opt_trace_object *trace_object) const
   {
 #ifdef OPTIMIZER_TRACE
-    trace_object->add_str("type", "index_group").
-      add_str("index", index_info->name, strlen(index_info->name));
+    trace_object->add_alnum("type", "index_group").
+      add_utf8("index", index_info->name);
     if (min_max_arg_part)
-      trace_object->add_str("group_attribute",
-                            min_max_arg_part->field->field_name,
-                            strlen(min_max_arg_part->field->field_name));
+      trace_object->add_utf8("group_attribute",
+                             min_max_arg_part->field->field_name);
     else
-      trace_object->add_str("group_attribute", "null");
+      trace_object->add_null("group_attribute");
     trace_object->add("min_aggregate", have_min).
       add("max_aggregate", have_max).
       add("distinct_aggregate", have_agg_distinct).
@@ -2300,7 +2242,7 @@ public:
       for (uint partno= 0; partno < used_key_parts; partno++)
       {
         const KEY_PART_INFO *cur_key_part= key_part + partno;
-        trace_keyparts.add_str(cur_key_part->field->field_name);
+        trace_keyparts.add_utf8(cur_key_part->field->field_name);
       }
     }
     Opt_trace_array trace_range(param->thd->opt_trace, "ranges");
@@ -2319,7 +2261,7 @@ public:
                      part->min_value, part->max_value,
                      part->min_flag | part->max_flag);
       }
-      trace_range.add_str(range_info.ptr(), range_info.length());
+      trace_range.add_utf8(range_info.ptr(), range_info.length());
     }
 #endif
   }
@@ -2558,19 +2500,18 @@ int SQL_SELECT::test_quick_select(THD *t
       for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
       {
         Opt_trace_object trace_idx_details(trace);
-        trace_idx_details.add_str("index",
-                                  key_info->name, strlen(key_info->name));
+        trace_idx_details.add_utf8("index", key_info->name);
         KEY_PART_INFO *key_part_info;
         if (!keys_to_use.is_set(idx))
         {
           trace_idx_details.add("usable", false).
-            add_str("cause", "not_usable_by_conditions");
+            add_alnum("cause", "not_usable_by_conditions");
           continue;
         }
         if (key_info->flags & HA_FULLTEXT)
         {
           trace_idx_details.add("usable", false).
-            add_str("cause", "fulltext");
+            add_alnum("cause", "fulltext");
           continue;    // ToDo: ft-keys in non-ft ranges, if possible   SerG
         }
 
@@ -2592,8 +2533,7 @@ int SQL_SELECT::test_quick_select(THD *t
             (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
           /* Only HA_PART_KEY_SEG is used */
           key_parts->flag=         (uint8) key_part_info->key_part_flag;
-          trace_keypart.add_str(key_parts->field->field_name,
-                                strlen(key_parts->field->field_name));
+          trace_keypart.add_utf8(key_parts->field->field_name);
         }
         param.real_keynr[param.keys++]=idx;
       }
@@ -2620,12 +2560,10 @@ int SQL_SELECT::test_quick_select(THD *t
       Opt_trace_object trace_cov(trace,
                                  "best_covering_index_scan",
                                  Opt_trace_context::RANGE_OPTIMIZER);
-      trace_cov.add_str("index", head->key_info[key_for_use].name,
-                        strlen(head->key_info[key_for_use].name)).
-        add("cost", key_read_time).
-        add("chosen", chosen);
+      trace_cov.add_utf8("index", head->key_info[key_for_use].name).
+        add("cost", key_read_time).add("chosen", chosen);
       if (!chosen)
-        trace_cov.add_str("cause", "cost");
+        trace_cov.add_alnum("cause", "cost");
     }
 
     TABLE_READ_PLAN *best_trp= NULL;
@@ -2652,7 +2590,7 @@ int SQL_SELECT::test_quick_select(THD *t
           DBUG_ASSERT(tree->type == SEL_TREE::ALWAYS); //anything else possible?
           trace_range.add("range_scan_possible", false);
           if (tree->type == SEL_TREE::ALWAYS) 
-            trace_range.add_str("cause", "condition_always_true");
+            trace_range.add_alnum("cause", "condition_always_true");
 
           tree= NULL;
         }
@@ -2679,7 +2617,7 @@ int SQL_SELECT::test_quick_select(THD *t
         best_read_time= best_trp->read_cost;
       }
       else
-        grp_summary.add("chosen", false).add_str("cause", "cost");
+        grp_summary.add("chosen", false).add_alnum("cause", "cost");
     }
 
     if (tree)
@@ -2804,6 +2742,8 @@ free_mem:
     thd->no_errors=0;
   }
 
+  DBUG_EXECUTE("info", print_quick(quick, &needed_reg););
+
   /*
     Assume that if the user is using 'limit' we will only need to scan
     limit rows if we are using a key
@@ -3164,7 +3104,7 @@ end:
 
 void store_key_image_to_rec(Field *field, uchar *ptr, uint len)
 {
-  /* Do the same as print_key() does */ 
+  /* Do the same as print_key_value() does */ 
   my_bitmap_map *old_map;
 
   if (field->real_maybe_null())
@@ -4167,7 +4107,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
     }
     if (imerge_too_expensive)
     {
-      trace_idx.add("chosen", false).add_str("cause", "cost");
+      trace_idx.add("chosen", false).add_alnum("cause", "cost");
       continue;
     }
 
@@ -4185,8 +4125,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
       non_cpk_scan_records += (*cur_child)->records;
 
     trace_idx.
-      add_str("index_to_merge", param->table->key_info[keynr_in_table].name,
-              strlen(param->table->key_info[keynr_in_table].name)).
+      add_utf8("index_to_merge", param->table->key_info[keynr_in_table].name).
       add("cumulated_cost", imerge_cost);
   }
 
@@ -4205,8 +4144,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
     */
     DBUG_PRINT("info", ("Sum of index_merge scans is more expensive than "
                         "full table scan, bailing out"));
-    trace_best_disjunct.add("chosen", false).
-      add_str("cause", "cost");
+    trace_best_disjunct.add("chosen", false).add_alnum("cause", "cost");
     DBUG_RETURN(NULL);
   }
 
@@ -4220,7 +4158,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
   {
     roru_read_plans= (TABLE_READ_PLAN**)range_scans;
     trace_best_disjunct.add("use_roworder_union", true).
-      add_str("cause", "always_cheaper_than_not_roworder_retrieval");
+      add_alnum("cause", "always_cheaper_than_not_roworder_retrieval");
     goto skip_to_ror_scan;
   }
 
@@ -4253,7 +4191,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
       !param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION))
   {
     trace_best_disjunct.add("use_roworder_index_merge", true).
-      add_str("cause", "cost");
+      add_alnum("cause", "cost");
     goto build_ror_index_merge;
   }
 
@@ -4944,7 +4882,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
   {
     if (tree->n_ror_scans < 2)
       trace_ror.add("usable", false).
-        add_str("cause", "too_few_roworder_scans");
+        add_alnum("cause", "too_few_roworder_scans");
     else
       trace_ror.add("usable", false).add("need_tracing", true);
     DBUG_RETURN(NULL);
@@ -5025,12 +4963,12 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
   {
     Opt_trace_object trace_idx(param->thd->opt_trace);
     char *idx_name= param->table->key_info[(*cur_ror_scan)->keynr].name;
-    trace_idx.add_str("index", idx_name, strlen(idx_name));
+    trace_idx.add_utf8("index", idx_name);
     /* S= S + first(R);  R= R - first(R); */
     if (!ror_intersect_add(intersect, *cur_ror_scan, FALSE))
     {
       trace_idx.add("usable", false).
-        add_str("cause", "does_not_reduce_cost_of_intersect");
+        add_alnum("cause", "does_not_reduce_cost_of_intersect");
       cur_ror_scan++;
       continue;
     }
@@ -5089,13 +5027,13 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
       }
       else
         trace_cpk.add("clustered_pk_added_to_intersect", false).
-          add_str("cause", "cost");
+          add_alnum("cause", "cost");
     }
     else
     {
       trace_cpk.add("clustered_pk_added_to_intersect", false).
-        add_str("cause", cpk_scan ?
-                "roworder_is_covering" : "no_clustered_pk_index");
+        add_alnum("cause", cpk_scan ?
+                  "roworder_is_covering" : "no_clustered_pk_index");
     }
   }
   /* Ok, return ROR-intersect plan if we have found one */
@@ -5364,8 +5302,7 @@ static TRP_RANGE *get_key_scans_params(P
                             (bool) param->table->covering_keys.is_set(keynr);
 
       Opt_trace_object trace_idx(param->thd->opt_trace);
-      trace_idx.add_str("index", param->table->key_info[keynr].name,
-                        strlen(param->table->key_info[keynr].name));
+      trace_idx.add_utf8("index", param->table->key_info[keynr].name);
 
       found_records= check_quick_select(param, idx, read_index_only, *key,
                                         update_tbl_stats, &mrr_flags,
@@ -5394,7 +5331,7 @@ static TRP_RANGE *get_key_scans_params(P
         best_buf_size=  buf_size;
       }
       else
-        trace_idx.add("chosen", false).add_str("cause", "cost");
+        trace_idx.add("chosen", false).add_alnum("cause", "cost");
 
     }
   }
@@ -6363,6 +6300,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
        field->type() == MYSQL_TYPE_DATETIME))
     field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
   {
+    // Note that value may be a stored function call, executed here
     err= value->save_in_field_no_warnings(field, 1);
   }
   if (err > 0)
@@ -6571,9 +6509,9 @@ end:
   {
     Opt_trace_object (param->thd->opt_trace, "impossible_condition",
                       Opt_trace_context::RANGE_OPTIMIZER).
-      add_str("table", *field->table_name, strlen(*field->table_name)).
-      add_str("field", field->field_name, strlen(field->field_name)).
-      add_str("cause", impossible_cond_cause);
+      add_utf8("table", *field->table_name).
+      add_utf8("field", field->field_name).
+      add_alnum("cause", impossible_cond_cause);
   }
   param->thd->mem_root= alloc;
   DBUG_RETURN(tree);
@@ -8269,7 +8207,7 @@ walk_up_n_right:
      */
     Opt_trace_struct *trace_range=  
       seq->param->thd->opt_trace->get_current_struct();
-    trace_range->add_str(key_range_trace.ptr(), key_range_trace.length());
+    trace_range->add_utf8(key_range_trace.ptr(), key_range_trace.length());
   }
 #endif
 
@@ -10266,8 +10204,7 @@ get_best_group_min_max(PARAM *param, SEL
          cur_index_info++, cur_index++)
     {
       Opt_trace_object trace_idx(thd->opt_trace);
-      trace_idx.add_str("index", cur_index_info->name, 
-                        strlen(cur_index_info->name));
+      trace_idx.add_utf8("index", cur_index_info->name);
       KEY_PART_INFO *cur_part;
       KEY_PART_INFO *end_part; /* Last part for loops. */
       /* Last index part. */
@@ -10581,7 +10518,7 @@ get_best_group_min_max(PARAM *param, SEL
   next_index:
       if (cause)
       {
-        trace_idx.add("usable", false).add_str("cause", cause);
+        trace_idx.add("usable", false).add_alnum("cause", cause);
         cause= NULL;
       }
     }
@@ -10631,12 +10568,12 @@ get_best_group_min_max(PARAM *param, SEL
 
 return_null_not_chosen_cause:
   DBUG_ASSERT(cause);
-  trace_group.add("chosen", false).add_str("cause", cause);
+  trace_group.add("chosen", false).add_alnum("cause", cause);
   DBUG_RETURN(NULL);
 
 return_null_not_usable_cause:
   DBUG_ASSERT(cause);
-  trace_group.add("usable", false).add_str("cause", cause);
+  trace_group.add("usable", false).add_alnum("cause", cause);
   DBUG_RETURN(NULL);
 }
 
@@ -12317,14 +12254,58 @@ static void print_ror_scans_arr(TABLE *t
 
 #endif /* !DBUG_OFF */
 
+#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
+
 /*****************************************************************************
-** Print a quick range for debugging
-** TODO:
-** This should be changed to use a String to store each row instead
-** of locking the DEBUG stream !
+** Append a range for a single keypart into a stream.
 *****************************************************************************/
 
-#if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
+/**
+  Print a key into a stream
+
+  @param[out] out          String the key is appended to
+  @param[in]  key_part     Index components description
+  @param[in]  key          Key tuple
+  @param[in]  used_length  Key tuple length
+*/
+static void
+print_key_value(String *out, const KEY_PART_INFO *key_part, const uchar *key)
+{
+  String tmp;
+  uint store_length;
+  TABLE *table= key_part->field->table;
+  my_bitmap_map *old_sets[2];
+
+  dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+
+  Field *field= key_part->field;
+  store_length= key_part->store_length;
+
+  if (field->real_maybe_null())
+  {
+    /*
+      Byte 0 of key is the null-byte. If set, key is NULL.
+      Otherwise, print the key value starting immediately after the
+      null-byte
+    */
+    if (*key)
+    {
+      out->append(STRING_WITH_LEN("NULL"));
+      goto restore_col_map;
+    }
+    key++;                                    // Skip null byte
+    store_length--;
+  }
+  field->set_key_image(key, key_part->length);
+  if (field->type() == MYSQL_TYPE_BIT)
+    (void) field->val_int_as_str(&tmp, 1); // may change tmp's charset
+  else
+    field->val_str(&tmp); // may change tmp's charset
+  out->append(tmp.ptr(), tmp.length(), tmp.charset());
+
+restore_col_map:
+  dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+}
 
 /**
   Append range info for a key part to a string
@@ -12365,7 +12346,53 @@ static void append_range(String *out,
   }
 }
 
-#if 0
+/*****************************************************************************
+** Print a quick range for debugging
+** TODO:
+** This should be changed to use a String to store each row instead
+** of locking the DEBUG stream !
+*****************************************************************************/
+
+static void
+print_multiple_key_values(KEY_PART *key_part, const uchar *key, 
+                          uint used_length)
+{
+  char buff[1024];
+  const uchar *key_end= key+used_length;
+  String tmp(buff,sizeof(buff),&my_charset_bin);
+  uint store_length;
+  TABLE *table= key_part->field->table;
+  my_bitmap_map *old_sets[2];
+
+  dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+
+  for (; key < key_end; key+=store_length, key_part++)
+  {
+    Field *field=      key_part->field;
+    store_length= key_part->store_length;
+
+    if (field->real_maybe_null())
+    {
+      if (*key)
+      {
+        fwrite("NULL",sizeof(char),4,DBUG_FILE);
+        continue;
+      }
+      key++;                                    // Skip null byte
+      store_length--;
+    }
+    field->set_key_image(key, key_part->length);
+    if (field->type() == MYSQL_TYPE_BIT)
+      (void) field->val_int_as_str(&tmp, 1);
+    else
+      field->val_str(&tmp);
+    fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
+    if (key+store_length < key_end)
+      fputc('/',DBUG_FILE);
+  }
+  dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+}
+
 static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
 {
   char buf[MAX_KEY/8+1];
@@ -12390,88 +12417,92 @@ static void print_quick(QUICK_SELECT_I *
   DBUG_UNLOCK_FILE;
   DBUG_VOID_RETURN;
 }
-#endif /* if 0*/
+
 void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
 {
-  Opt_trace_context *out= current_thd->opt_trace;
-  Opt_trace_object oto(out, "range_scan");
-  oto.add_str("index", head->key_info[index].name,
-              strlen(head->key_info[index].name)).
-    add("key_length", max_used_key_length).
-    add("used_keyparts", used_key_parts);
- 
-  Opt_trace_array trace_range(out, "ranges");
   /* purecov: begin inspected */
-  if (TRUE)
+  fprintf(DBUG_FILE, "%*squick range select, key %s, length: %d\n",
+          indent, "", head->key_info[index].name, max_used_key_length);
+
+  if (verbose)
   {
     QUICK_RANGE *range;
     QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
     QUICK_RANGE **end_range= pr + ranges.elements;
     for (; pr != end_range; ++pr)
     {
-      String range_info;
-      range_info.set_charset(system_charset_info);
+      fprintf(DBUG_FILE, "%*s", indent + 2, "");
       range= *pr;
-      append_range(&range_info, head->key_info[index].key_part,
-                   range->min_key, range->max_key,
-                   range->flag);
-      trace_range.add_str(range_info.ptr(), range_info.length());
+      if (!(range->flag & NO_MIN_RANGE))
+      {
+        print_multiple_key_values(key_parts, range->min_key,
+                                  range->min_length);
+        if (range->flag & NEAR_MIN)
+          fputs(" < ",DBUG_FILE);
+        else
+          fputs(" <= ",DBUG_FILE);
+      }
+      fputs("X",DBUG_FILE);
+
+      if (!(range->flag & NO_MAX_RANGE))
+      {
+        if (range->flag & NEAR_MAX)
+          fputs(" < ",DBUG_FILE);
+        else
+          fputs(" <= ",DBUG_FILE);
+        print_multiple_key_values(key_parts, range->max_key,
+                                  range->max_length);
+      }
+      fputs("\n",DBUG_FILE);
     }
   }
-  /* purecov: end */    
+  /* purecov: end */
 }
 
 void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
 {
-  Opt_trace_context *out= current_thd->opt_trace;
   List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
   QUICK_RANGE_SELECT *quick;
-  /* purecov: begin inspected */
-  Opt_trace_array ota(out, "index_merge");
+  fprintf(DBUG_FILE, "%*squick index_merge select\n", indent, "");
+  fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
   while ((quick= it++))
-  {
-    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
-  }
   if (pk_quick_select)
   {
-    Opt_trace_object oto2(out, "clustered_pk_scan");
+    fprintf(DBUG_FILE, "%*sclustered PK quick:\n", indent, "");
     pk_quick_select->dbug_dump(indent+2, verbose);
   }
+  fprintf(DBUG_FILE, "%*s}\n", indent, "");
 }
 
 void QUICK_ROR_INTERSECT_SELECT::dbug_dump(int indent, bool verbose)
 {
-  Opt_trace_context *out= current_thd->opt_trace;
   List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
   QUICK_RANGE_SELECT *quick;
-  Opt_trace_array ota(out, "index_roworder_intersect");
+  fprintf(DBUG_FILE, "%*squick ROR-intersect select, %scovering\n",
+          indent, "", need_to_fetch_row? "":"non-");
+  fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
   while ((quick= it++))
-  {
-    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
-  }
   if (cpk_quick)
   {
-    Opt_trace_object oto2(out, "clustered_pk_scan");
+    fprintf(DBUG_FILE, "%*sclustered PK quick:\n", indent, "");
     cpk_quick->dbug_dump(indent+2, verbose);
   }
+  fprintf(DBUG_FILE, "%*s}\n", indent, "");
 }
 
 void QUICK_ROR_UNION_SELECT::dbug_dump(int indent, bool verbose)
 {
-  Opt_trace_context *out= current_thd->opt_trace;
   List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
   QUICK_SELECT_I *quick;
-  Opt_trace_array ota(out, "index_roworder_union");
+  fprintf(DBUG_FILE, "%*squick ROR-union select\n", indent, "");
+  fprintf(DBUG_FILE, "%*smerged scans {\n", indent, "");
   while ((quick= it++))
-  {
-    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
-  }
+  fprintf(DBUG_FILE, "%*s}\n", indent, "");
 }
 
-
 /*
   Print quick select information to DBUG_FILE.
 
@@ -12494,14 +12525,9 @@ void QUICK_ROR_UNION_SELECT::dbug_dump(i
 
 void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
 {
-  Opt_trace_context *out= current_thd->opt_trace;
-  Opt_trace_object oto(out, "index_group");
-  oto.add_str("index", index_info->name, strlen(index_info->name)).
-    add("key_length", max_used_key_length);
-
   fprintf(DBUG_FILE,
           "%*squick_group_min_max_select: index %s (%d), length: %d\n",
-	  indent, "", index_info->name, index, max_used_key_length);
+          indent, "", index_info->name, index, max_used_key_length);
   if (key_infix_len > 0)
   {
     fprintf(DBUG_FILE, "%*susing key_infix with length %d:\n",
@@ -12519,6 +12545,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::dbug_du
   }
 }
 
+
 #endif /* !DBUG_OFF || OPTIMIZER_TRACE */
 
 /*****************************************************************************

=== modified file 'sql/opt_trace.cc'
--- a/sql/opt_trace.cc	2010-11-11 13:25:53 +0000
+++ b/sql/opt_trace.cc	2010-11-24 18:54:26 +0000
@@ -25,6 +25,7 @@
 #include "opt_trace.h"
 #include "mysqld.h"    // system_charset_info
 #include "item.h"      // Item
+#include "m_string.h"  // _dig_vec_lower
 
 #ifdef OPTIMIZER_TRACE
 
@@ -85,9 +86,9 @@ void Opt_trace_struct::do_construct(Opt_
     if (stmt->current_struct != NULL)
     {
       if (key != NULL)
-        stmt->current_struct->add_str(key, "...");
+        stmt->current_struct->add_alnum(key, "...");
       else
-        stmt->current_struct->add_str("...");
+        stmt->current_struct->add_alnum("...");
     }
     stmt->support_I_S= false; // disable tracing for this struct and children
   }
@@ -107,24 +108,26 @@ void Opt_trace_struct::do_construct(Opt_
         continuation. That will be visible in the OS_MALLOC_ERROR column.
       */
       size_t new_size= alloced + increment;
-      const size_t max_size= stmt->buffer.allowed_mem_size;
-      if (new_size > max_size) // don't pre-allocate more than the limit
-        new_size= max_size;
-      const size_t overhead=
-        1 + (ALIGN_SIZE(1) - 1) // see start of String::realloc()
-        /*
-          Stay strictly below max_size or it would trigger truncation at
-          next append(), which is potentially wrong for a "pre-emptive
-          allocation" as we do here.
-        */
-        + 1;
-      if (new_size >= overhead)
+      size_t max_size= stmt->buffer.allowed_mem_size;
+      /*
+        Determine a safety margin:
+        (A) String::realloc() adds at most ALIGN_SIZE(1) bytes to requested
+        length, so we need to decrement max_size by this amount, to be sure that
+        we don't allocate more than max_size
+        (B) We need to stay at least one byte under that max_size, or the next
+        append() would trigger up-front truncation, which is potentially wrong
+        for a "pre-emptive allocation" as we do here.
+      */
+      const size_t safety_margin= ALIGN_SIZE(1) /* (A) */ + 1 /* (B) */;
+      if (max_size >= safety_margin)
       {
-        new_size-= overhead;
+        max_size-= safety_margin;
+        if (new_size > max_size) // don't pre-allocate more than the limit
+          new_size= max_size;
         if (new_size >= alloced) // never shrink string
           stmt->buffer.realloc(new_size);
       }
-  }
+    }
   }
   if (likely(parent != NULL))
     parent->add_struct(key);
@@ -154,7 +157,7 @@ void Opt_trace_struct::add_key_name(cons
       Check that we're not having two identical consecutive keys in one
       object; though the real restriction should not have 'consecutive'.
     */
-    DBUG_ASSERT(strcmp(previous_key, key) != 0);
+    DBUG_ASSERT(strncmp(previous_key, key, sizeof(previous_key) - 1) != 0);
     strncpy(previous_key, key, sizeof(previous_key) - 1);
     previous_key[sizeof(previous_key) - 1]= 0;
 #endif
@@ -378,12 +381,11 @@ const char *Opt_trace_context::flag_name
 
 const char *Opt_trace_context::feature_names[]=
 {
-  "misc", "greedy_search", "range_optimizer", "default", NullS
+  "greedy_search", "range_optimizer", "default", NullS
 };
 
 const Opt_trace_context::feature_value Opt_trace_context::FEATURES_DEFAULT=
-  Opt_trace_context::feature_value(Opt_trace_context::MISC |
-                                   Opt_trace_context::GREEDY_SEARCH |
+  Opt_trace_context::feature_value(Opt_trace_context::GREEDY_SEARCH |
                                    Opt_trace_context::RANGE_OPTIMIZER);
 
 Opt_trace_context::Opt_trace_context(void):
@@ -539,7 +541,7 @@ bool Opt_trace_context::start(bool suppo
                               long offset_arg,
                               long limit_arg,
                               ulong max_mem_size_arg,
-                              feature_value features_arg)
+                              ulonglong features_arg)
 {
   DBUG_ENTER("Opt_trace_context::start");
   /*
@@ -578,7 +580,7 @@ bool Opt_trace_context::start(bool suppo
     offset= offset_arg;
     limit= limit_arg;
     max_mem_size= max_mem_size_arg;
-    features= features_arg;
+    features= feature_value(features_arg | MISC); // MISC always on
   }
   /*
     Decide whether to-be-created trace should support I_S.
@@ -928,33 +930,31 @@ bool Opt_trace_stmt::Buffer::append_esca
 #endif
     {
       rc= false;
-      /*
-        The JSON syntax mandates that those characters be escaped:
-        \ " \b \f \n \r \t
-        It also mentions escaping / , but Python's and Perl's json modules
-        do not require it, and somewhere on Internet someone said JSON
-        allows escaping of / but does not require it.
-      */
       const char *pstr, *pstr_end;
       char buf[128] /* temporary output buffer*/, *pbuf= buf;
       for (pstr= str, pstr_end= (str + length) ; pstr < pstr_end ; pstr++)
       {
         char esc;
         const char c= *pstr;
+        /*
+          JSON syntax says that control characters must be escaped. Experience
+          confirms that this means ASCII 0->31 and " and \ . A few of
+          them are accepted with a short escaping syntax (using \ : like
+          \n) but for most of them, only \uXXXX works, where XXXX is an
+          hexadecimal value for the code point.
+          Rules also mention escaping / , but Python's and Perl's json modules
+          do not require it, and somewhere on Internet someone said JSON
+          allows escaping of / but does not require it.
+        */
         switch (c)
         {
+          // don't use \u when possible for common chars, \ is easier to read:
         case '\\':
           esc= '\\';
           break;
         case '"':
           esc= '\"';
           break;
-        case '\b':
-          esc= 'b';
-          break;
-        case '\f':
-          esc= 'f';
-          break;
         case '\n':
           esc= 'n';
           break;
@@ -964,27 +964,44 @@ bool Opt_trace_stmt::Buffer::append_esca
         case '\t':
           esc= 't';
           break;
-        case '\0': // Python's 'json' module has a problem with unescaped NUL
-          esc= '0';
-          break;
-          ///@todo should we escape ctrl-Z for Windows (see String::print())?
         default:
-          esc= 0; // other character, so no escaping needed
+          esc= 0;
           break;
         }
-        if (pbuf > buf + (sizeof(buf) - 2))
-        {
-          /* no room in 'buf' for 2 chars, so flush it */
-          rc|= String::append(buf, pbuf - buf);
-          pbuf= buf; // back to buf's start
-        }
-        if (esc)
+        if (esc != 0)                           // escaping with backslash
         {
           *pbuf++= '\\';
           *pbuf++= esc;
         }
         else
-          *pbuf++= c;
+        {
+          uint ascii_code= (uint)c;
+          if (ascii_code < 32)                  // escaping with \u
+          {
+            *pbuf++= '\\';
+            *pbuf++= 'u';
+            *pbuf++= '0';
+            *pbuf++= '0';
+            if (ascii_code < 16)
+            {
+              *pbuf++= '0';
+            }
+            else
+            {
+              *pbuf++= '1';
+              ascii_code-= 16;
+            }
+            *pbuf++= _dig_vec_lower[ascii_code];
+          }
+          else
+            *pbuf++= c; // normal character, no escaping needed
+        }
+        if (pbuf > buf + (sizeof(buf) - 6))
+        {
+          /* no room in 'buf' for next char, so flush it */
+          rc|= String::append(buf, pbuf - buf);
+          pbuf= buf; // back to buf's start
+        }
       }
       /* flush any chars left in 'buf' */
       rc|= String::append(buf, pbuf - buf);

=== modified file 'sql/opt_trace.h'
--- a/sql/opt_trace.h	2010-11-17 12:27:39 +0000
+++ b/sql/opt_trace.h	2010-12-19 14:24:03 +0000
@@ -21,7 +21,8 @@
 class THD;
 #include "my_base.h"    // ha_rows
 #include "sql_string.h" // String
-
+#include "sql_list.h"   // because sql_cmd.h needs it
+#include "sql_cmd.h"    // for enum_sql_command
 
 /**
    @file
@@ -368,7 +369,6 @@ public:
   /**
      Features' names for @@@@optimizer_trace_features variable of
      @c sys_vars.cc:
-     @li "misc" = anything unclassified
      @li "greedy_search" = the greedy search for a plan
      @li "range_optimizer" = the cost analysis of accessing data through
      ranges in indices
@@ -377,15 +377,19 @@ public:
   static const char *feature_names[];
   /** Features' numeric values for @@@@optimizer_trace_features variable */
   enum feature_value {
+    GREEDY_SEARCH= 1,
+    RANGE_OPTIMIZER= 2, ///@todo join cache, semijoin...
+    /*
+      if you add here, update feature_value of empty implementation
+      and FEATURES_DEFAULT!
+    */
     /**
        Anything unclassified, including the top object (thus, by "inheritance
        from parent", disabling MISC makes an empty trace).
+       This feature cannot be disabled by the user; for this it is important
+       that it always has biggest flag; flag's value itself does not matter
     */
-    MISC= 1,
-    GREEDY_SEARCH= 2,
-    RANGE_OPTIMIZER= 4 ///@todo join cache, semijoin...
-    /* if you add here, update feature_value of empty implementation
-     * and FEATURES_DEFAULT! */
+    MISC= 128
   };
   static const feature_value FEATURES_DEFAULT;
 
@@ -419,7 +423,7 @@ public:
   */
   bool start(bool need_it_for_I_S, bool end_marker, bool one_line,
              long offset, long limit, ulong max_mem_size,
-             feature_value features);
+             ulonglong features);
   /** Ends the current trace */
   void end(void);
   /** Returns whether there is a current trace */
@@ -773,9 +777,22 @@ public:
 
   /**
      Adds a value (of string type) to the structure. A key is specified, so it
-     is adds the key/value pair (the structure must thus be an object).
+     adds the key/value pair (the structure must thus be an object).
+
+     There are two "add_*" variants to add a string value.
+     If the value is 0-terminated and each character
+     - is ASCII 7-bit
+     - has code >=32 and is neither '"' nor '\\'
+     then add_alnum() should be used. That should be the case for all fixed
+     strings like add_alnum("cause", "cost").
+     Otherwise, add_utf8() should be used; it accepts any UTF8-encoded character
+     in 'value' and will escape characters which JSON requires (and is thus
+     slower than add_alnum()). It should be used for all strings which we get
+     from the server's objects (indeed a table's name, a WHERE condition, may
+     contain "strange" characters).
+
      @param  key    key
-     @param  value  value, in ASCII
+     @param  value  value
      @param  val_length  length of string 'value'
      @return a reference to the structure, useful for chaining like this:
      @verbatim add(x,y).add(z,t).add(u,v) @endverbatim
@@ -804,7 +821,7 @@ public:
      unusually intensive on the optimizer and thus real-life cases should have
      a smaller penalty. This will be benchmarked with the QA teams.
 
-     String-related add() variants are named add_str():
+     String-related add() variants are named add_[something]():
      - to avoid confusing the compiler between:
      add(const char *value, size_t    val_length) and
      add(const char *key,   ulonglong value)
@@ -814,50 +831,60 @@ public:
      add(const char *key,   double value) instead of
      add(const char *value, size_t val_length).
   */
-  Opt_trace_struct& add_str(const char *key,
-                            const char *value, size_t val_length)
+  Opt_trace_struct& add_alnum(const char *key,
+                              const char *value)
   {
     if (likely(!started))
       return *this;
-    return do_add(key, value, val_length, false);
+    return do_add(key, value, strlen(value), false);
   }
   /**
-     Like add() but for non-ASCII strings.
+     Adds a value (of string type) to the structure. No key is specified, so
+     it adds only the value (the structure must thus be an array).
+     @param  value  value
+     @return a reference to the structure
+  */
+  Opt_trace_struct& add_alnum(const char *value)
+  {
+    if (likely(!started))
+      return *this;
+    return do_add(NULL, value, strlen(value), false);
+  }
+  /**
+     Like add_alnum() but supports any UTF8 characters in 'value'.
      Will "escape" 'value' to be JSON-compliant.
      @param  key
-     @param  value       value, in UTF8
+     @param  value       value
      @param  val_length  length of string 'value'
   */
-  Opt_trace_struct& add_str_escaped(const char *key,
-                                    const char *value, size_t val_length)
+  Opt_trace_struct& add_utf8(const char *key,
+                             const char *value, size_t val_length)
   {
     if (likely(!started))
       return *this;
     return do_add(key, value, val_length, true);
   }
-  Opt_trace_struct& add_str(const char *key, const char *value)
+  /** Variant of add_utf8() for adding to an array (no key) */
+  Opt_trace_struct& add_utf8(const char *value, size_t val_length)
   {
     if (likely(!started))
       return *this;
-    return do_add(key, value, strlen(value), false);
+    return do_add(NULL, value, val_length, true);
   }
-  /**
-     Adds a value (of string type) to the structure. No key is specified, so
-     it adds only the value (the structure must thus be an array).
-     @param  value  value, in ASCII
-     @return a reference to the structure
-  */
-  Opt_trace_struct& add_str(const char *value, size_t val_length)
+  /** Variant of add_utf8() where 'value' is 0-terminated */
+  Opt_trace_struct& add_utf8(const char *key,
+                             const char *value)
   {
     if (likely(!started))
       return *this;
-    return do_add(NULL, value, val_length, false);
+    return do_add(key, value, strlen(value), true);
   }
-  Opt_trace_struct& add_str(const char *value)
+  /** Variant of add_utf8() where 'value' is 0-terminated */
+  Opt_trace_struct& add_utf8(const char *value)
   {
     if (likely(!started))
       return *this;
-    return do_add(NULL, value, strlen(value), false);
+    return do_add(NULL, value, strlen(value), true);
   }
   /**
      Add a value (of Item type) to the structure. The Item should be a
@@ -952,6 +979,12 @@ public:
       return *this;
     return do_add(NULL, value);
   }
+  Opt_trace_struct& add_null(const char *key)
+  {
+    if (likely(!started))
+      return *this;
+    return do_add_null(key);
+  }
   /**
     The exception to RAII: this function is an explicit way to end a
     structure before it goes out of scope. Don't use it unless RAII mandates
@@ -1083,7 +1116,7 @@ public:
 
 /**
    A JSON object (unordered set of key/value pairs).
-   Defines only a constructor, all the rest in inherited from Opt_trace_struct.
+   Defines only a constructor, all the rest is inherited from Opt_trace_struct.
 */
 class Opt_trace_object: public Opt_trace_struct
 {
@@ -1119,7 +1152,8 @@ class Opt_trace_array: public Opt_trace_
 {
 public:
   /**
-     Constructs an array. @sa Opt_trace_object::Opt_trace_object.
+     Constructs an array. Key is specified, so the array is the value of a
+     key/value pair.
      @param  ctx  context for this array
      @param  key  key
   */
@@ -1127,6 +1161,11 @@ public:
                   Opt_trace_context::feature_value feature=
                   Opt_trace_context::MISC) :
   Opt_trace_struct(ctx, false, key, feature) {}
+  /**
+     Constructs an array. No key is specified, so the array is just a value
+     (serves for adding the object to an array).
+     @param  ctx  context for this array
+  */
   Opt_trace_array(Opt_trace_context *ctx,
                   Opt_trace_context::feature_value feature=
                   Opt_trace_context::MISC) :
@@ -1206,7 +1245,7 @@ private:
 #define OPT_TRACE(trace, action) do {                                  \
     if (unlikely((trace) != NULL))                                     \
       if (unlikely((trace)->is_started()))                             \
-        (trace)->get_current_struct()->action;                            \
+        (trace)->get_current_struct()->action;                         \
   } while (0)
 
 
@@ -1232,18 +1271,17 @@ struct TABLE_LIST;
   Start tracing a THD's actions (generally at a statement's start).
   @param  thd  the THD
   @param  tbl  list of tables read/written by the statement.
+  @param  sql_command  SQL command being prepared or executed
   @return whether this function decided to trace (and thus the corresponding
   opt_trace_end() should end the trace).
   @note if tracing was already started (by a top statement above the present
-  sub-statement in the call chain), and this function decides to trace the
-  sub-statement, it returns "true". For example in
-  @verbatim EXECUTE prepared_stmt @endverbatim @c mysql_execute_command() is
-  called as usual, and from inside it, @c mysql_execute_command() is
-  called. The first call starts one trace, the second call starts a separate
-  new trace; at the end of the second call the second trace is terminated; at
-  the end of the first call the first trace is terminated.
+  sub-statement in the call chain), and this function decides to trace
+  (respectively not trace) the sub-statement, it returns "true"
+  (resp. false). Each sub-statement is responsible for ending the trace which it
+  has started.
 */
-bool opt_trace_start(THD *thd, const TABLE_LIST *tbl);
+bool opt_trace_start(THD *thd, const TABLE_LIST *tbl,
+                     enum enum_sql_command sql_command);
 
 /**
   Stop tracing a THD's actions (generally at statement's end).
@@ -1309,8 +1347,12 @@ int make_optimizer_trace_table_for_show(
 class Opt_trace_context
 {
 public:
-  /* We need this one */
-  enum feature_value { MISC= 1, GREEDY_SEARCH= 2, RANGE_OPTIMIZER= 4 };
+  /// We need this enum even if tracing is disabled
+  enum feature_value {
+    GREEDY_SEARCH= 1,
+    RANGE_OPTIMIZER= 2,
+    MISC= 128
+  };
 };
 
 /** Empty implementation used when optimizer trace is not compiled in */
@@ -1323,10 +1365,12 @@ public:
   Opt_trace_object(Opt_trace_context *ctx,
                    Opt_trace_context::feature_value feature=
                    Opt_trace_context::MISC) {}
-  Opt_trace_object& add_str(const char *key,
-                            const char *value, size_t val_length)
+  Opt_trace_object& add_alnum(const char *key, const char *value)
   { return *this; }
-  Opt_trace_object& add_str(const char *key, const char *value)
+  Opt_trace_object& add_utf8(const char *key,
+                             const char *value, size_t val_length)
+  { return *this; }
+  Opt_trace_object& add_utf8(const char *key, const char *value)
   { return *this; }
   Opt_trace_object& add(const char *key, Item *item) { return *this; }
   Opt_trace_object& add(const char *key, bool value) { return *this; }
@@ -1335,6 +1379,7 @@ public:
   Opt_trace_object& add(const char *key, longlong value) { return *this; }
   Opt_trace_object& add(const char *key, ulonglong value) { return *this; }
   Opt_trace_object& add(const char *key, double value) { return *this; }
+  void end(void) {}
 };
 
 /** Empty implementation used when optimizer trace is not compiled in */
@@ -1347,9 +1392,11 @@ public:
   Opt_trace_array(Opt_trace_context *ctx,
                   Opt_trace_context::feature_value feature=
                   Opt_trace_context::MISC) {}
-  Opt_trace_array& add_str(const char *value, size_t val_length)
+  Opt_trace_array& add_alnum(const char *value) { return *this; }
+  Opt_trace_array& add_utf8(const char *value, size_t val_length)
+  { return *this; }
+  Opt_trace_array& add_utf8(const char *value)
   { return *this; }
-  Opt_trace_array& add_str(const char *value) { return *this; }
   Opt_trace_array& add(Item *item) { return *this; }
   Opt_trace_array& add(bool value) { return *this; }
   Opt_trace_array& add(int value) { return *this; }
@@ -1357,6 +1404,7 @@ public:
   Opt_trace_array& add(longlong value) { return *this; }
   Opt_trace_array& add(ulonglong value) { return *this; }
   Opt_trace_array& add(double value) { return *this; }
+  void end(void) {}
 };
 
 /** Empty implementation used when optimizer trace is not compiled in */
@@ -1369,7 +1417,7 @@ public:
 #define OPT_TRACE(trace, action) do {} while (0)
 #define OPT_TRACE2(trace, action) do {} while (0)
 
-#define opt_trace_start(thd, tbl) (false)
+#define opt_trace_start(thd, tbl, sql_command) (false)
 #define opt_trace_end(thd, started) do {} while (0)
 #define opt_trace_print_expanded_query(thd) do {} while (0)
 #define opt_trace_add_select_number(s, select_number) do {} while (0)
@@ -1396,10 +1444,18 @@ public:
    @param to             description of the after-transformation state
 */
 #define OPT_TRACE_TRANSFO(trace,object_level0,object_level1,select_number,from,to) \
-    Opt_trace_object object_level0(trace);                              \
-    Opt_trace_object object_level1(trace, "transformation");            \
-    opt_trace_add_select_number(&object_level1, select_number);         \
-    object_level1.add_str("from", from).add_str("to", to);
+  Opt_trace_object object_level0(trace);                                \
+  Opt_trace_object object_level1(trace, "transformation");              \
+  opt_trace_add_select_number(&object_level1, select_number);           \
+  object_level1.add_alnum("from", from).add_alnum("to", to);
+
+/**
+   Helper to put the database/table name in the trace
+   @param  t  TABLE* pointer
+*/
+#define add_utf8_table(t)                                               \
+  add_utf8("database", (t)->s->db.str, (t)->s->db.length).              \
+  add_utf8("table", (t)->alias)
 
 #if !defined(DBUG_OFF) && !defined(OPTIMIZER_TRACE)
 
@@ -1410,10 +1466,4 @@ public:
 #error debug binaries must support optimizer trace
 #endif
 
-/**
-   The trace for range optimizer isn't mastered, and breaks.
-   @todo fix this.
-*/
-#define NO_OPT_TRACE_FOR_RANGE_OPT 1
-
 #endif /* OPT_TRACE_INCLUDED */

=== modified file 'sql/opt_trace2server.cc'
--- a/sql/opt_trace2server.cc	2010-10-21 15:22:32 +0000
+++ b/sql/opt_trace2server.cc	2010-12-19 14:24:03 +0000
@@ -29,7 +29,7 @@
 
 #include "opt_trace.h"
 #include "sql_show.h"  // schema_table_stored_record()
-#include "sql_class.h" // THD
+#include "sql_parse.h" // sql_command_flags
 
 #ifdef OPTIMIZER_TRACE
 
@@ -56,7 +56,39 @@ static bool list_has_optimizer_trace_tab
 }
 
 
-bool opt_trace_start(THD *thd, const TABLE_LIST *tbl)
+/**
+   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)
+{
+  /*
+    Tracing is limited to a few SQL commands only.
+
+    Reasons to not trace other commands:
+    - it reduces the range of potential unknown bugs and misuse
+    - they probably don't have anything interesting optimizer-related
+    - select_lex for them might be uninitialized and unprintable.
+    - SHOW WARNINGS would create an uninteresting trace and thus overwrite the
+    previous interesting one.
+
+    About prepared statements: note that we don't turn on tracing for
+    SQLCOM_PREPARE (respectively SQLCOM_EXECUTE), because we don't know yet what
+    command is being prepared (resp. executed). We turn tracing on later, if the
+    prepared (resp. executed) command is in the allowed set above, in
+    check_prepared_statement() (resp. mysql_execute_command() called by
+    Prepared_statement::execute()).
+    PREPARE SELECT is worth tracing as it does permanent query transformations.
+
+    Note that SELECT includes EXPLAIN.
+  */
+  return (sql_command_flags[sql_command] & CF_OPTIMIZER_TRACE);
+}
+
+
+bool opt_trace_start(THD *thd, const TABLE_LIST *tbl,
+                     enum enum_sql_command sql_command)
 {
   DBUG_ENTER("opt_trace_start");
 
@@ -66,41 +98,67 @@ bool opt_trace_start(THD *thd, const TAB
     * if we are using --debug (because the trace serves as a relay for it, for
     optimizer debug printouts).
     Additionally, we should not be tracing if:
-    * we are already tracing (see function comment of opt_trace_start())
+    * command is not interesting (optimizer-wise)
     * query involves I_S.OPTIMIZER_TRACE (we do not want to overwrite the
     trace while reading it with SELECT).
   */
   ulonglong var= thd->variables.optimizer_trace;
   bool need_it_for_I_S= (var & Opt_trace_context::FLAG_ENABLED);
-  bool need_it_for_dbug= false, ret= false;
+  bool need_it_for_dbug= false, allocated_here= false;
   /* This will be triggered if --debug or --debug=d:opt_trace is used */
   DBUG_EXECUTE("opt_trace", need_it_for_dbug= true;);
   if (!(need_it_for_I_S || need_it_for_dbug))
-    goto end;
+    goto disable;
+  if (!sql_command_can_be_traced(sql_command))
+    goto disable;
   if (list_has_optimizer_trace_table(tbl))
-    goto end;
+    goto disable;
   /*
     We don't allocate it in THD's MEM_ROOT as it must survive until a next
     statement (SELECT) reads the trace.
   */
   if (thd->opt_trace == NULL)
+  {
     if ((thd->opt_trace= new Opt_trace_context()) == NULL)
-      goto end;
+      goto disable;
+    allocated_here= true;
+  }
+start_trace:
   if (thd->opt_trace->start(need_it_for_I_S,
                             (var & Opt_trace_context::FLAG_END_MARKER),
                             (var & Opt_trace_context::FLAG_ONE_LINE),
                             thd->variables.optimizer_trace_offset,
                             thd->variables.optimizer_trace_limit,
                             thd->variables.optimizer_trace_max_mem_size,
-                            Opt_trace_context::feature_value(thd->variables.optimizer_trace_features)))
+                            thd->variables.optimizer_trace_features))
+  {
+    if (allocated_here)
+    {
+      delete thd->opt_trace;
+      thd->opt_trace= NULL;
+    }
+    goto disable;
+  }
+  DBUG_RETURN(true); // started all ok
+disable:
+  /*
+    No need to create a trace for this statement.
+    Exception: imagine there is a parent statement which has a trace, and we
+    don't create a trace for the child statement here. Then trace structures of
+    the child will be accidentally attached to the parent's trace (as
+    it is still 'current_stmt_in_gen', which constructors of Opt_trace_struct
+    will use); thus the child's trace will be visible (as a chunk of the
+    parent's trace). That would be incorrect.
+    To avoid this, we create a trace for the child but with I_S output disabled;
+    this changes 'current_stmt_in_gen', thus this child's trace structures
+    will be attached to the child's trace and not be visible.
+  */
+  if (need_it_for_I_S && thd->opt_trace != NULL && thd->opt_trace->is_started())
   {
-    delete thd->opt_trace;
-    thd->opt_trace= NULL;
-    goto end;
-  }
-  ret= true; // started all ok
-end:
-  DBUG_RETURN(ret);
+    need_it_for_I_S= false;
+    goto start_trace;
+  }
+  DBUG_RETURN(false);
 }
 
 
@@ -115,24 +173,23 @@ void opt_trace_end(THD *thd, bool starte
 
 void opt_trace_print_expanded_query(THD *thd)
 {
-  Opt_trace_context *trace= thd->opt_trace;
+  Opt_trace_context * const trace= thd->opt_trace;
   if (trace == NULL || !trace->is_started())
     return;
-  switch (thd->lex->sql_command)
-  {
-  case SQLCOM_SELECT:
-  case SQLCOM_INSERT:
-  case SQLCOM_INSERT_SELECT:
-  case SQLCOM_REPLACE_SELECT:
-  case SQLCOM_UPDATE:
-  case SQLCOM_DELETE:
-  case SQLCOM_UPDATE_MULTI:
-  case SQLCOM_DELETE_MULTI:
-    break;
-  default:
-    /* select_lex for other commands might be uninitialized, don't print */
+  /*
+    In "SELECT stored_func()" , execution of a
+    sub-statement of stored_func() may start by opening tables (that's the case
+    of DECLARE which opens tables (actually an empty list of tables) and does
+    not go through mysql_execute_command()). So we may arrive here,
+    print the "expanded query" of this sub-statement even before
+    opt_trace_start() has been called for it (it may never be called for it
+    at all). Thus trying to put the expanded query inside the parent statement's
+    trace, which would be logically wrong and possibly a syntax error.
+    thd->lex->sql_command is SQLCOM_END in this case. So we do a check of the
+    command:
+  */
+  if (!sql_command_can_be_traced(thd->lex->sql_command))
     return;
-  }
   char buff[1024];
   String str(buff,(uint32) sizeof(buff), system_charset_info);
   str.length(0);
@@ -145,8 +202,7 @@ void opt_trace_print_expanded_query(THD 
   */
   thd->lex->unit.print(&str, enum_query_type(QT_EXPAND_VIEW_DEFINITION |
                                              QT_SHOW_SELECT_NUMBER));
-  Opt_trace_object(trace).add_str_escaped("expanded_query",
-                                          str.ptr(), str.length());
+  Opt_trace_object(trace).add_utf8("expanded_query", str.ptr(), str.length());
 }
 
 
@@ -156,7 +212,7 @@ void opt_trace_add_select_number(Opt_tra
   if (unlikely(select_number >= INT_MAX))
   {
     /* clearer than any huge number */
-    s->add_str("select#", "fake");
+    s->add_alnum("select#", "fake");
   }
   else
     s->add("select#", select_number);
@@ -181,11 +237,10 @@ int fill_optimizer_trace_info(THD *thd, 
       const Opt_trace_info info= *it;
       restore_record(table, s->default_values);
       /*
-        We will put the query, which is in character_set_client (except
-        literals with introducers) into a column using
-        character_set_client; this is better than UTF8 (see BUG#57306). If
-        literals with introducers are used, which we cannot know (that would
-        require looking at the parse tree), it may be wrong, some say.
+        We will put the query, which is in character_set_client, into a column
+        using character_set_client; this is better than UTF8 (see BUG#57306).
+        When literals with introducers are used, see "LiteralsWithIntroducers"
+        in this file.
       */
       table->field[0]->store(info.query_ptr, info.query_length, info.query_charset);
       table->field[1]->store(info.trace_ptr, info.trace_length, system_charset_info);
@@ -242,4 +297,34 @@ int make_optimizer_trace_table_for_show(
   return 0;
 }
 
+/*
+  LiteralsWithIntroducers :
+
+  They may be significantly altered; but this isn't specific to the optimizer
+  trace, it also happens with SHOW PROCESSLIST, and is deemed a not too
+  important problem.
+
+  Consider
+  mysql> set names latin1;
+  mysql> SELECT 'í', _cp850'í';
+  | í | Ý |
+  This sends the binary string:
+  SELECT <0xED>, _cp850<0xED>
+  to the server (í is 0xED in latin1).
+  Now we put this into OPTIMIZER_TRACE.QUERY, using latin1
+  (character_set_client), and the client has switched to utf8: we convert the
+  query from latin1 to utf8 when sending to client, which receives:
+  SELECT <0xC3><0xAD>, _cp850<0xC3><0xAD>
+  (í is <0xC3><0xAD> in utf8).
+  But <0xC3><0xAD> in _cp850 means a completely different character:
+  mysql> set names utf8;
+  mysql> SELECT 'í', _cp850'í';
+  | í  | ├¡    |
+
+  If the client had originally issued
+  SELECT 'í', _cp850 0xED;
+  there would be no problem ('0', 'x', 'E', and 'D' are identical in latin1 and
+  utf8: they would be preserved during conversion).
+*/
+
 #endif // OPTIMIZER_TRACE

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-09-27 09:26:39 +0000
+++ b/sql/sql_class.h	2010-11-26 17:29:04 +0000
@@ -3577,6 +3577,9 @@ public:
 */
 #define CF_CAN_GENERATE_ROW_EVENTS (1U << 11)
 
+/** Identifies statements which may generate an optimizer trace */
+#define CF_OPTIMIZER_TRACE (1U << 12)
+
 /* Bits in server_command_flags */
 
 /**

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2010-11-22 09:59:17 +0000
+++ b/sql/sql_delete.cc	2010-11-24 18:54:26 +0000
@@ -193,9 +193,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
 
   { // Enter scope for optimizer trace wrapper
     Opt_trace_object wrapper(thd->opt_trace);
-    wrapper.add_str("database", table_list->db,
-                    strlen(table_list->db)).
-      add_str("table", table_list->alias, strlen(table_list->alias));
+    wrapper.add_utf8_table(table);
 
     if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
     {

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-11-06 09:56:51 +0000
+++ b/sql/sql_parse.cc	2010-12-19 14:24:03 +0000
@@ -294,28 +294,38 @@ void init_update_queries(void)
 
   sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
+  // This is INSERT VALUES(...), can be VALUES(stored_func()) so we trace it
   sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
                                             CF_PROTECT_AGAINST_GRL |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_SELECT]=         CF_REEXECUTION_FRAGILE |
-                                            CF_CAN_GENERATE_ROW_EVENTS;
+                                            CF_CAN_GENERATE_ROW_EVENTS |
+                                            CF_OPTIMIZER_TRACE;
   sql_command_flags[SQLCOM_SET_OPTION]=     CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
   sql_command_flags[SQLCOM_DO]=             CF_REEXECUTION_FRAGILE |
                                             CF_CAN_GENERATE_ROW_EVENTS;
@@ -1884,7 +1894,6 @@ mysql_execute_command(THD *thd)
   /* have table map for update for multi-update statement (BUG#37051) */
   bool have_table_map_for_update= FALSE;
 #endif
-  bool started_optimizer_trace= false;
   /* Saved variable value */
   DBUG_ENTER("mysql_execute_command");
 #ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -2058,19 +2067,11 @@ mysql_execute_command(THD *thd)
 
   status_var_increment(thd->status_var.com_stat[lex->sql_command]);
 
-  if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) == 0)
-  {
-    if ((started_optimizer_trace= opt_trace_start(thd, all_tables)))
-      opt_trace_set_query(thd->opt_trace, thd->query(), thd->query_length(),
-                          thd->variables.character_set_client);
-  }
-  else
-  {
-    /*
-      We don't want SHOW WARNINGS to start a trace, it would overwrite the
-      previous statement's trace.
-    */
-  }
+  const bool started_optimizer_trace= opt_trace_start(thd, all_tables,
+                                                      lex->sql_command);
+  if (started_optimizer_trace)
+    opt_trace_set_query(thd->opt_trace, thd->query(), thd->query_length(),
+                        thd->variables.character_set_client);
 
   Opt_trace_object trace_command(thd->opt_trace);
   Opt_trace_array trace_command_steps(thd->opt_trace, "steps");

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2010-08-18 10:18:27 +0000
+++ b/sql/sql_prepare.cc	2010-12-19 14:24:03 +0000
@@ -1964,6 +1964,20 @@ static bool check_prepared_statement(Pre
   if (tables)
     thd->warning_info->opt_clear_warning_info(thd->query_id);
 
+  /*
+    For the optimizer trace, this is the symmetric, for statement preparation,
+    of what is done at statement execution (in mysql_execute_command()).
+  */
+  const bool started_optimizer_trace= opt_trace_start(thd, tables,
+                                                      sql_command);
+  if (started_optimizer_trace)
+    opt_trace_set_query(thd->opt_trace, thd->query(), thd->query_length(),
+                        thd->variables.character_set_client);
+
+
+  Opt_trace_object trace_command(thd->opt_trace);
+  Opt_trace_array trace_command_steps(thd->opt_trace, "steps");
+
   switch (sql_command) {
   case SQLCOM_REPLACE:
   case SQLCOM_INSERT:
@@ -2006,7 +2020,8 @@ static bool check_prepared_statement(Pre
     if (res == 2)
     {
       /* Statement and field info has already been sent */
-      DBUG_RETURN(FALSE);
+      res= FALSE;
+      goto end;
     }
     break;
   case SQLCOM_CREATE_TABLE:
@@ -2017,7 +2032,8 @@ static bool check_prepared_statement(Pre
     if (lex->create_view_mode == VIEW_ALTER)
     {
       my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
-      goto error;
+      res= true;
+      goto end;
     }
     res= mysql_test_create_view(stmt);
     break;
@@ -2090,15 +2106,19 @@ static bool check_prepared_statement(Pre
     {
       /* All other statements are not supported yet. */
       my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
-      goto error;
+      res= true;
+      goto end;
     }
     break;
   }
   if (res == 0)
-    DBUG_RETURN(stmt->is_sql_prepare() ?
-                FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
-error:
-  DBUG_RETURN(TRUE);
+    res= stmt->is_sql_prepare() ?
+      FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush());
+end:
+  trace_command_steps.end();
+  trace_command.end(); // must be closed before trace is ended below
+  opt_trace_end(thd, started_optimizer_trace);
+  DBUG_RETURN(res);
 }
 
 /**

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-11-22 09:59:17 +0000
+++ b/sql/sql_select.cc	2010-11-24 18:54:26 +0000
@@ -167,8 +167,7 @@ end_update(JOIN *join, JOIN_TAB *join_ta
 static enum_nested_loop_state
 end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records);
 
-static int join_read_const_table(JOIN_TAB *tab, POSITION *pos,
-                                 Opt_trace_array *trace_array);
+static int join_read_const_table(JOIN_TAB *tab, POSITION *pos);
 static int join_read_system(JOIN_TAB *tab);
 static int join_read_const(JOIN_TAB *tab);
 static int join_read_key(JOIN_TAB *tab);
@@ -991,7 +990,7 @@ bool resolve_subquery(THD *thd, JOIN *jo
                         "IN (SELECT)", "materialization");
       oto1.add("chosen", choice == 2);
       if (types_problem)
-        oto1.add_str("cause", "field types");
+        oto1.add_alnum("cause", "field_types");
     }
   }
 
@@ -2666,7 +2665,7 @@ setup_subq_exit:
   DBUG_ASSERT(zero_result_cause != NULL);
   trace_steps.end();   // because all steps are done
   Opt_trace_object trace_empty_result(trace, "empty_result");
-  trace_empty_result.add_str("cause", zero_result_cause);
+  trace_empty_result.add_alnum("cause", zero_result_cause);
   /*
     Even with zero matching rows, subqueries in the HAVING clause may
     need to be evaluated if there are aggregate functions in the
@@ -4118,7 +4117,7 @@ skip_conversion:
                         (*subq)->get_select_lex()->select_number,
                         "IN (SELECT)", "semijoin");
       if (outer_join_objection)
-        oto1.add_str("cause", "outer_join");
+        oto1.add_alnum("cause", "outer_join");
       oto1.add("chosen", false);
     }
     JOIN *child_join= (*subq)->unit->first_select()->join;
@@ -4350,9 +4349,7 @@ int pull_out_semijoin_tables(JOIN *join)
         if (tbl->table->map & join->const_table_map)
         {
           pulled_tables |= tbl->table->map;
-          Opt_trace_object(trace).
-            add_str("database", tbl->db, strlen(tbl->db)).
-            add_str("table", tbl->alias, strlen(tbl->alias)).
+          Opt_trace_object(trace).add_utf8_table(tbl->table).
             add("constant", true);
         }
       }
@@ -4378,9 +4375,7 @@ int pull_out_semijoin_tables(JOIN *join)
           {
             pulled_a_table= TRUE;
             pulled_tables |= tbl->table->map;
-            Opt_trace_object(trace).
-              add_str("database", tbl->db, strlen(tbl->db)).
-              add_str("table", tbl->alias, strlen(tbl->alias)).
+            Opt_trace_object(trace).add_utf8_table(tbl->table).
               add("functionally_dependent", true);
             /*
               Pulling a table out of uncorrelated subquery in general makes
@@ -4743,194 +4738,187 @@ make_join_statistics(JOIN *join, TABLE_L
 
   {
     Opt_trace_object trace_wrapper(trace);
+    for (POSITION *p_pos= join->positions, *p_end= p_pos + const_count;
+         p_pos < p_end ;
+         p_pos++)
+    {
+      int tmp;
+      s= p_pos->table;
+      s->type= JT_SYSTEM;
+      join->const_table_map|= s->table->map;
+      if ((tmp= join_read_const_table(s, p_pos)))
+      {
+        if (tmp > 0)
+          goto error;		// Fatal error
+      }
+      else
+      {
+        found_const_table_map|= s->table->map;
+        s->table->pos_in_table_list->optimized_away= TRUE;
+      }
+    }
+
+    /* loop until no more const tables are found */
+    int ref_changed;
+    do
     {
-      Opt_trace_array trace_const_tables(trace, "constant_tables");
+  more_const_tables_found:
+      ref_changed = 0;
+      found_ref= 0;
 
-      for (POSITION *p_pos= join->positions, *p_end= p_pos + const_count;
-           p_pos < p_end ;
-           p_pos++)
-      {
-        int tmp;
-        s= p_pos->table;
-        s->type= JT_SYSTEM;
-        join->const_table_map|= s->table->map;
-        if ((tmp= join_read_const_table(s, p_pos, &trace_const_tables)))
-        {
-          if (tmp > 0)
-            goto error;		// Fatal error
-        }
-        else
-        {
-          found_const_table_map|= s->table->map;
-          s->table->pos_in_table_list->optimized_away= TRUE;
-        }
-      }
+      /*
+        We only have to loop from stat_vector + const_count as
+        set_position() will move all const_tables first in stat_vector
+      */
 
-      /* loop until no more const tables are found */
-      int ref_changed;
-      do
+      for (JOIN_TAB **pos= stat_vector + const_count ; (s= *pos) ; pos++)
       {
-    more_const_tables_found:
-        ref_changed = 0;
-        found_ref= 0;
+        table= s->table;
 
         /*
-          We only have to loop from stat_vector + const_count as
-          set_position() will move all const_tables first in stat_vector
+          If equi-join condition by a key is null rejecting and after a
+          substitution of a const table the key value happens to be null
+          then we can state that there are no matches for this equi-join.
         */
-
-        for (JOIN_TAB **pos= stat_vector + const_count ; (s= *pos) ; pos++)
+        if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map)
         {
-          table= s->table;
-
           /*
-             If equi-join condition by a key is null rejecting and after a
-             substitution of a const table the key value happens to be null
-             then we can state that there are no matches for this equi-join.
+            When performing an outer join operation if there are no matching rows
+            for the single row of the outer table all the inner tables are to be
+            null complemented and thus considered as constant tables.
+            Here we apply this consideration to the case of outer join operations
+            with a single inner table only because the case with nested tables
+            would require a more thorough analysis.
+            TODO. Apply single row substitution to null complemented inner tables
+            for nested outer join operations.
           */
-          if ((keyuse= s->keyuse) && *s->on_expr_ref && !s->embedding_map)
+          while (keyuse->table == table)
           {
-            /*
-               When performing an outer join operation if there are no matching rows
-               for the single row of the outer table all the inner tables are to be
-               null complemented and thus considered as constant tables.
-               Here we apply this consideration to the case of outer join operations
-               with a single inner table only because the case with nested tables
-               would require a more thorough analysis.
-               TODO. Apply single row substitution to null complemented inner tables
-               for nested outer join operations.
-            */
-            while (keyuse->table == table)
+            if (!(keyuse->val->used_tables() & ~join->const_table_map) &&
+                keyuse->val->is_null() && keyuse->null_rejecting)
             {
-              if (!(keyuse->val->used_tables() & ~join->const_table_map) &&
-                  keyuse->val->is_null() && keyuse->null_rejecting)
-              {
-                s->type= JT_CONST;
-                mark_as_null_row(table);
-                found_const_table_map|= table->map;
-                join->const_table_map|= table->map;
-                set_position(join, const_count++, s, (KEYUSE*) 0);
-                goto more_const_tables_found;
-              }
-              keyuse++;
+              s->type= JT_CONST;
+              mark_as_null_row(table);
+              found_const_table_map|= table->map;
+              join->const_table_map|= table->map;
+              set_position(join, const_count++, s, (KEYUSE*) 0);
+              goto more_const_tables_found;
             }
+            keyuse++;
           }
+        }
 
-          if (s->dependent)				// If dependent on some table
-          {
-            // All dep. must be constants
-            if (s->dependent & ~(join->const_table_map))
-              continue;
-            if (table->file->stats.records <= 1L &&
-                (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
-                !table->pos_in_table_list->in_outer_join_nest())
-            {					// system table
-              int tmp= 0;
-              s->type= JT_SYSTEM;
-              join->const_table_map|= table->map;
-              set_position(join, const_count++, s, (KEYUSE*) 0);
-              if ((tmp= join_read_const_table(s, join->positions +
-                                              const_count - 1,
-                                              &trace_const_tables)))
-              {
-                if (tmp > 0)
-                  goto error;			// Fatal error
-              }
-              else
-                found_const_table_map|= table->map;
-              continue;
+        if (s->dependent)				// If dependent on some table
+        {
+          // All dep. must be constants
+          if (s->dependent & ~(join->const_table_map))
+            continue;
+          if (table->file->stats.records <= 1L &&
+              (table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
+              !table->pos_in_table_list->in_outer_join_nest())
+          {					// system table
+            int tmp= 0;
+            s->type= JT_SYSTEM;
+            join->const_table_map|= table->map;
+            set_position(join, const_count++, s, (KEYUSE*) 0);
+            if ((tmp= join_read_const_table(s, join->positions +
+                                            const_count - 1)))
+            {
+              if (tmp > 0)
+                goto error;			// Fatal error
             }
+            else
+              found_const_table_map|= table->map;
+            continue;
           }
-          /* check if table can be read by key or table only uses const refs */
-          if ((keyuse= s->keyuse))
+        }
+        /* check if table can be read by key or table only uses const refs */
+        if ((keyuse= s->keyuse))
+        {
+          s->type= JT_REF;
+          while (keyuse->table == table)
           {
-            s->type= JT_REF;
-            while (keyuse->table == table)
+            start_keyuse= keyuse;
+            key= keyuse->key;
+            s->keys.set_bit(key);               // QQ: remove this ?
+
+            refs= 0;
+            key_map const_ref, eq_part;
+            do
             {
-              start_keyuse= keyuse;
-              key= keyuse->key;
-              s->keys.set_bit(key);               // QQ: remove this ?
-
-              refs= 0;
-              key_map const_ref, eq_part;
-              do
+              if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
               {
-                if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
-                {
-                  if (!((~found_const_table_map) & keyuse->used_tables))
-                    const_ref.set_bit(keyuse->keypart);
-                  else
-                    refs|= keyuse->used_tables;
-                  eq_part.set_bit(keyuse->keypart);
-                }
-                keyuse++;
-              } while (keyuse->table == table && keyuse->key == key);
+                if (!((~found_const_table_map) & keyuse->used_tables))
+                  const_ref.set_bit(keyuse->keypart);
+                else
+                  refs|= keyuse->used_tables;
+                eq_part.set_bit(keyuse->keypart);
+              }
+              keyuse++;
+            } while (keyuse->table == table && keyuse->key == key);
 
-              /*
-                TODO (low priority): currently we ignore the const tables that
-                are within a semi-join nest which is within an outer join nest.
-                The effect of this is that we don't do const substitution for
-                such tables.
-              */
-              if (eq_part.is_prefix(table->key_info[key].key_parts) &&
-                  !table->fulltext_searched &&
-                  !table->pos_in_table_list->in_outer_join_nest())
+            /*
+              TODO (low priority): currently we ignore the const tables that
+              are within a semi-join nest which is within an outer join nest.
+              The effect of this is that we don't do const substitution for
+              such tables.
+            */
+            if (eq_part.is_prefix(table->key_info[key].key_parts) &&
+                !table->fulltext_searched &&
+                !table->pos_in_table_list->in_outer_join_nest())
+            {
+              if (table->key_info[key].flags & HA_NOSAME)
               {
-                if (table->key_info[key].flags & HA_NOSAME)
-                {
-                  if (const_ref == eq_part)
-                  {					// Found everything for ref.
-                    int tmp;
-                    ref_changed = 1;
-                    s->type= JT_CONST;
-                    join->const_table_map|= table->map;
-                    set_position(join, const_count++, s, start_keyuse);
-                    if (create_ref_for_key(join, s, start_keyuse,
-                                           found_const_table_map))
-                      goto error;
-                    if ((tmp= join_read_const_table(s,
-                                                    join->positions +
-                                                    const_count - 1,
-                                                    &trace_const_tables)))
-                    {
-                      if (tmp > 0)
-                        goto error;			// Fatal error
-                    }
-                    else
-                      found_const_table_map|= table->map;
-                    break;
+                if (const_ref == eq_part)
+                {					// Found everything for ref.
+                  int tmp;
+                  ref_changed = 1;
+                  s->type= JT_CONST;
+                  join->const_table_map|= table->map;
+                  set_position(join, const_count++, s, start_keyuse);
+                  if (create_ref_for_key(join, s, start_keyuse,
+                                         found_const_table_map))
+                    goto error;
+                  if ((tmp= join_read_const_table(s,
+                                                  join->positions +
+                                                  const_count - 1)))
+                  {
+                    if (tmp > 0)
+                      goto error;			// Fatal error
                   }
                   else
-                    found_ref|= refs;      // Table is const if all refs are const
+                    found_const_table_map|= table->map;
+                  break;
                 }
-                else if (const_ref == eq_part)
-                  s->const_keys.set_bit(key);
+                else
+                  found_ref|= refs;      // Table is const if all refs are const
               }
+              else if (const_ref == eq_part)
+                s->const_keys.set_bit(key);
             }
           }
         }
-      } while (join->const_table_map & found_ref && ref_changed);
+      }
+    } while (join->const_table_map & found_ref && ref_changed);
 
-      /*
-         Update info on indexes that can be used for search lookups as
-         reading const tables may has added new sargable predicates. 
-      */
-      if (const_count && sargables)
+    /*
+      Update info on indexes that can be used for search lookups as
+      reading const tables may has added new sargable predicates. 
+    */
+    if (const_count && sargables)
+    {
+      for( ; sargables->field ; sargables++)
       {
-        for( ; sargables->field ; sargables++)
-        {
-          Field *field= sargables->field;
-          JOIN_TAB *join_tab= field->table->reginfo.join_tab;
-          key_map possible_keys= field->key_start;
-          possible_keys.intersect(field->table->keys_in_use_for_query);
-          bool is_const= 1;
-          for (uint j= 0; j < sargables->num_values; j++)
-            is_const&= sargables->arg_value[j]->const_item();
-          if (is_const)
-            join_tab[0].const_keys.merge(possible_keys);
-        }
+        Field *field= sargables->field;
+        JOIN_TAB *join_tab= field->table->reginfo.join_tab;
+        key_map possible_keys= field->key_start;
+        possible_keys.intersect(field->table->keys_in_use_for_query);
+        bool is_const= 1;
+        for (uint j= 0; j < sargables->num_values; j++)
+          is_const&= sargables->arg_value[j]->const_item();
+        if (is_const)
+          join_tab[0].const_keys.merge(possible_keys);
       }
-
     }
 
     {
@@ -4940,14 +4928,12 @@ make_join_statistics(JOIN *join, TABLE_L
       for (s= stat ; s < stat_end ; s++)
       {
         Opt_trace_object trace_table(trace);
-        trace_table.add_str("database",s->join->tables_list->db,
-                            strlen(s->join->tables_list->db)).
-          add_str("table", s->table->alias, strlen(s->table->alias));
+        trace_table.add_utf8_table(s->table);
         if (s->type == JT_SYSTEM || s->type == JT_CONST)
         {
           trace_table.add("records", 1).add("cost", 1);
-          trace_table.add_str("table_type", (s->type == JT_SYSTEM) ?
-                              "system": "const");
+          trace_table.add_alnum("table_type", (s->type == JT_SYSTEM) ?
+                                "system": "const");
 
           /* Only one matching row */
           s->found_records= s->records= s->read_time=1; s->worst_seeks= 1.0;
@@ -5012,7 +4998,7 @@ make_join_statistics(JOIN *join, TABLE_L
               /* Generate empty row */
               s->info= "Impossible ON condition";
               trace_table.add("returning_empty_null_row", true).
-                add_str("cause", "impossible_on_condition");
+                add_alnum("cause", "impossible_on_condition");
               found_const_table_map|= s->table->map;
               s->type= JT_CONST;
               mark_as_null_row(s->table);		// All fields are NULL
@@ -5020,7 +5006,7 @@ make_join_statistics(JOIN *join, TABLE_L
             else 
             {
               trace_table.add("records", 0).
-                add_str("cause", "impossible_where_condition");
+                add_alnum("cause", "impossible_where_condition");
             }
           }
           if (records != HA_POS_ERROR)
@@ -6564,6 +6550,7 @@ static void trace_indices_added_group_di
                                                const key_map new_keys,
                                                const char* cause)
 {
+#ifdef OPTIMIZER_TRACE
   if (likely(trace == NULL) || !trace->is_started())
     return;
 
@@ -6576,9 +6563,10 @@ static void trace_indices_added_group_di
     Opt_trace_array trace_key(trace,"keys");
     for (uint j= 0 ; j < nbrkeys ; j++)
       if (new_keys.is_set(j) && !existing_keys.is_set(j))
-        trace_key.add_str(key_info[j].name, strlen(key_info[j].name));
+        trace_key.add_utf8(key_info[j].name);
   }
-  trace_summary.add_str("cause", cause);
+  trace_summary.add_alnum("cause", cause);
+#endif
 }
 
 
@@ -7021,8 +7009,8 @@ best_access_path(JOIN      *join,
       DBUG_PRINT("info", ("Considering ref access on key %s",
                           keyuse->table->key_info[keyuse->key].name));
       Opt_trace_object trace_access_idx(trace);
-      trace_access_idx.add_str("access_type", "ref").
-        add_str("index", keyinfo->name, strlen(keyinfo->name));
+      trace_access_idx.add_alnum("access_type", "ref").
+        add_utf8("index", keyinfo->name);
 
       /* 
          True if we find some keys from the range optimizer that match more
@@ -7408,10 +7396,10 @@ best_access_path(JOIN      *join,
   */
   if (!(records >= s->found_records || best > s->read_time))            // (1)
   {
-    trace_access_scan.add_str("access_type", s->quick ? "range" : "scan");
+    trace_access_scan.add_alnum("access_type", s->quick ? "range" : "scan");
     trace_access_scan.add("cost", s->read_time).
       add("records", s->found_records).
-      add_str("cause", "cost");
+      add_alnum("cause", "cost");
 
     goto skip_table_scan;
   }
@@ -7419,23 +7407,23 @@ best_access_path(JOIN      *join,
   if ((s->quick && best_key && s->quick->index == best_key->key &&      // (2)
        best_max_key_part >= s->table->quick_key_parts[best_key->key]))  // (2)
   {
-    trace_access_scan.add_str("access_type", "range").
-      add_str("cause", "heuristic_index_cheaper");
+    trace_access_scan.add_alnum("access_type", "range").
+      add_alnum("cause", "heuristic_index_cheaper");
     goto skip_table_scan;
   }
 
   if (((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) &&     // (3)
        ! s->table->covering_keys.is_clear_all() && best_key && !s->quick))// (3)
   {
-    trace_access_scan.add_str("access_type", s->quick ? "range" : "scan").
-      add_str("cause", "covering_index_better_than_full_scan");
+    trace_access_scan.add_alnum("access_type", s->quick ? "range" : "scan").
+      add_alnum("cause", "covering_index_better_than_full_scan");
     goto skip_table_scan;
   }
 
   if ((s->table->force_index && best_key && !s->quick))                 // (4)
   {
-      trace_access_scan.add_str("access_type", "scan").
-        add_str("cause", "force_index");
+      trace_access_scan.add_alnum("access_type", "scan").
+        add_alnum("cause", "force_index");
     goto skip_table_scan;
   }
 
@@ -7468,7 +7456,7 @@ best_access_path(JOIN      *join,
 
     if (s->quick)
     {
-      trace_access_scan.add_str("access_type", "range");
+      trace_access_scan.add_alnum("access_type", "range");
       /*
         For each record we:
         - read record range through 'quick'
@@ -7486,7 +7474,7 @@ best_access_path(JOIN      *join,
     }
     else
     {
-      trace_access_scan.add_str("access_type", "scan");
+      trace_access_scan.add_alnum("access_type", "scan");
       /* Estimate cost of reading table. */
       if (s->table->force_index && !best_key)
         tmp= s->table->file->read_time(s->ref.key, 1, s->records);
@@ -8319,10 +8307,7 @@ best_extension_by_limited_search(JOIN   
       double current_record_count, current_read_time;
       POSITION *position= join->positions + idx;
       Opt_trace_object trace_one_table(trace);
-      trace_one_table.
-        add_str("database", s->join->tables_list->db,
-                strlen(s->join->tables_list->db)).
-        add_str("table", s->table->alias, strlen(s->table->alias));
+      trace_one_table.add_utf8_table(s->table);
 
       /* Find the best access method from 's' to the current partial plan */
       POSITION loose_scan_pos;
@@ -8743,11 +8728,8 @@ static bool fix_semijoin_strategies_for_
         Opt_trace_object oto0(trace);
         Opt_trace_object oto1(trace,
                               "reconsidering_access_paths_for_semijoin");
-        oto1.add_str("strategy", "MaterializationScan").
-          add_str("database", join->tables_list->db, 
-                  strlen(join->tables_list->db)).
-          add_str("table", join->best_positions[i].table->table->alias,
-                  strlen(join->best_positions[i].table->table->alias));
+        oto1.add_alnum("strategy", "MaterializationScan").
+          add_utf8_table(join->best_positions[i].table->table);
         best_access_path(join, join->best_positions[i].table, rem_tables, i, FALSE,
                          prefix_rec_count, join->best_positions + i, &dummy);
         prefix_rec_count *= join->best_positions[i].records_read;
@@ -8783,11 +8765,8 @@ static bool fix_semijoin_strategies_for_
           Opt_trace_object oto0(trace);
           Opt_trace_object oto1(trace,
                                 "reconsidering_access_paths_for_semijoin");
-          oto1.add_str("strategy", "FirstMatch").
-            add_str("database", join->tables_list->db, 
-                    strlen(join->tables_list->db)).
-            add_str("table", join->best_positions[idx].table->table->alias,
-                    strlen(join->best_positions[idx].table->table->alias));
+          oto1.add_alnum("strategy", "FirstMatch").
+            add_utf8_table(join->best_positions[idx].table->table);
           best_access_path(join, join->best_positions[idx].table, 
                            rem_tables, idx, TRUE /* no jbuf */,
                            record_count, join->best_positions + idx, &dummy);
@@ -8820,11 +8799,8 @@ static bool fix_semijoin_strategies_for_
           Opt_trace_object oto0(trace);
           Opt_trace_object oto1(trace,
                                 "reconsidering_access_paths_for_semijoin");
-          oto1.add_str("strategy", "LooseScan").
-            add_str("database", join->tables_list->db, 
-                    strlen(join->tables_list->db)).
-            add_str("table", join->best_positions[idx].table->table->alias,
-                    strlen(join->best_positions[idx].table->table->alias));
+          oto1.add_alnum("strategy", "LooseScan").
+            add_utf8_table(join->best_positions[idx].table->table);
           best_access_path(join, join->best_positions[idx].table,
                            rem_tables, idx, TRUE /* no jbuf */,
                            record_count, join->best_positions + idx,
@@ -9698,9 +9674,7 @@ static bool make_join_select(JOIN *join,
     {
       tab= join->join_tab+i;
       Opt_trace_object trace_one_table(thd->opt_trace);
-      trace_one_table.add_str("database", join->tables_list->db,
-                              strlen(join->tables_list->db)).
-        add_str("table", tab->table->alias, strlen(tab->table->alias));
+      trace_one_table.add_utf8_table(tab->table);
       /*
         first_inner is the X in queries like:
         SELECT * FROM t1 LEFT OUTER JOIN (t2 JOIN t3) ON X
@@ -11182,9 +11156,7 @@ make_join_readinfo(JOIN *join, ulonglong
     pick_table_access_method (tab);
 
     Opt_trace_object trace_refine_table(trace);
-    trace_refine_table.add_str("database", join->tables_list->db,
-                              strlen(join->tables_list->db)).
-      add_str("table", table->alias, strlen(table->alias));
+    trace_refine_table.add_utf8_table(table);
 
     if (tab->loosescan_match_tab)
     {
@@ -11311,8 +11283,8 @@ make_join_readinfo(JOIN *join, ulonglong
             tab->select->quick->index != MAX_KEY && ! tab->table->key_read)
           push_index_cond(tab, tab->select->quick->index, icp_other_tables_ok);
       }
-      trace_refine_table.add_str("scan_type",
-                                 tab->type==JT_NEXT ? "index" : "table");
+      trace_refine_table.add_alnum("scan_type",
+                                   tab->type == JT_NEXT ? "index" : "table");
       break;
     case JT_FT:
       break;
@@ -13843,7 +13815,7 @@ void optimize_wo_join_buffering(JOIN *jo
   DBUG_ENTER("optimize_wo_join_buffering");
 
   Opt_trace_object trace_recompute(trace, "recompute_best_access_paths");
-  trace_recompute.add_str("cause", "join_buffering_not_possible");
+  trace_recompute.add_alnum("cause", "join_buffering_not_possible");
   Opt_trace_array trace_tables(trace, "tables");
 
   if (first_tab > join->const_tables)
@@ -13869,10 +13841,7 @@ void optimize_wo_join_buffering(JOIN *jo
     {
       /* Find the best access method that would not use join buffering */
       Opt_trace_object trace_one_table(trace);
-      trace_one_table.add_str("database", join->tables_list->db, 
-                              strlen(join->tables_list->db));
-      trace_one_table.add_str("table", rs->table->alias, 
-                              strlen(rs->table->alias));
+      trace_one_table.add_utf8_table(rs->table);
       best_access_path(join, rs, reopt_remaining_tables, i, 
                        i < no_jbuf_before, inner_fanout * outer_fanout,
                        &pos, &loose_scan_pos);
@@ -14072,7 +14041,7 @@ void advance_sj_state(JOIN *join, table_
         double reopt_cost, reopt_rec_count;
         /* We use the same FirstLetterUpcase as in EXPLAIN */
         Opt_trace_object trace_one_strategy(trace);
-        trace_one_strategy.add_str("strategy", "FirstMatch");
+        trace_one_strategy.add_alnum("strategy", "FirstMatch");
         optimize_wo_join_buffering(join, pos->first_firstmatch_table, idx,
                                    remaining_tables, FALSE, idx,
                                    &reopt_rec_count, &reopt_cost);
@@ -14143,7 +14112,7 @@ void advance_sj_state(JOIN *join, table_
       /* Got a complete LooseScan range. Calculate its cost */
       double reopt_cost, reopt_rec_count;
       Opt_trace_object trace_one_strategy(trace);
-      trace_one_strategy.add_str("strategy", "LooseScan");
+      trace_one_strategy.add_alnum("strategy", "LooseScan");
       /*
         The same problem as with FirstMatch - we need to save POSITIONs
         somewhere but reserving space for all cases would require too
@@ -14220,8 +14189,8 @@ void advance_sj_state(JOIN *join, table_
       emb_sj_nest->sj_inner_tables | 
       emb_sj_nest->nested_join->sj_depends_on;
     pos->sjm_scan_last_inner= idx;
-    Opt_trace_object(trace).add_str("strategy", "MaterializationScan").
-      add_str("choice", "deferred");
+    Opt_trace_object(trace).add_alnum("strategy", "MaterializationScan").
+      add_alnum("choice", "deferred");
   }
   else if (sjm_strategy == SJ_OPT_MATERIALIZE_LOOKUP)
   {
@@ -14245,7 +14214,7 @@ void advance_sj_state(JOIN *join, table_
       prefix_rec_count * emb_sj_nest->nested_join->sjm.lookup_cost.total_cost();
 
     Opt_trace_object trace_one_strategy(trace);
-    trace_one_strategy.add_str("strategy", "MaterializationLookup").
+    trace_one_strategy.add_alnum("strategy", "MaterializationLookup").
       add("cost", mat_read_time).add("records", prefix_rec_count).
       add("duplicate_tables_left", pos->dups_producing_tables != 0);
     if (mat_read_time < *current_read_time || pos->dups_producing_tables)
@@ -14278,7 +14247,7 @@ void advance_sj_state(JOIN *join, table_
     int first_tab= pos->sjm_scan_last_inner + 1 - table_count;
 
     Opt_trace_object trace_one_strategy(trace);
-    trace_one_strategy.add_str("strategy", "MaterializationScan");
+    trace_one_strategy.add_alnum("strategy", "MaterializationScan");
 
     /* Get the prefix cost */
     if (first_tab == (int)join->const_tables)
@@ -14307,16 +14276,13 @@ void advance_sj_state(JOIN *join, table_
     /* Need to re-run best-access-path as we prefix_rec_count has changed */
     {
       Opt_trace_object trace_recompute(trace, "recompute_best_access_paths");
-      trace_recompute.add_str("cause", "costs_of_prefix_changed");
+      trace_recompute.add_alnum("cause", "costs_of_prefix_changed");
       Opt_trace_array trace_tables(trace, "tables");
 
       for (i= first_tab + table_count; i <= idx; i++)
       {
         Opt_trace_object trace_one_table(trace);
-        trace_one_table.add_str("database", join->tables_list->db,
-                                strlen(join->tables_list->db)).
-          add_str("table", join->positions[i].table->table->alias,
-              strlen(join->positions[i].table->table->alias));
+        trace_one_table.add_utf8_table(join->positions[i].table->table);
         best_access_path(join, join->positions[i].table, rem_tables, i, FALSE,
                          prefix_rec_count, &curpos, &dummy);
         prefix_rec_count *= curpos.records_read;
@@ -14443,7 +14409,7 @@ void advance_sj_state(JOIN *join, table_
         leave duplicate-producing tables not handled by any strategy.
       */
       Opt_trace_object trace_one_strategy(trace);
-      trace_one_strategy.add_str("strategy", "DuplicatesWeedout").
+      trace_one_strategy.add_alnum("strategy", "DuplicatesWeedout").
         add("cost", dups_cost).
         add("records", prefix_rec_count * sj_outer_fanout).
         add("duplicate_tables_left", pos->dups_producing_tables != 0);
@@ -14597,7 +14563,7 @@ optimize_cond(JOIN *join, Item *conds, L
   {
     Opt_trace_object trace_wrapper(trace);
     Opt_trace_object trace_cond(trace, "condition_processing");
-    trace_cond.add_str("condition", build_equalities ? "WHERE" : "HAVING");
+    trace_cond.add_alnum("condition", build_equalities ? "WHERE" : "HAVING");
     /* 
       Build all multiple equality predicates and eliminate equality
       predicates that can be inferred from these multiple equalities.
@@ -18015,8 +17981,7 @@ int safe_index_read(JOIN_TAB *tab)
    @retval <0  ??
 */
 static int
-join_read_const_table(JOIN_TAB *tab, POSITION *pos,
-                      Opt_trace_array *trace_array)
+join_read_const_table(JOIN_TAB *tab, POSITION *pos)
 {
   int error;
   DBUG_ENTER("join_read_const_table");
@@ -18025,7 +17990,6 @@ join_read_const_table(JOIN_TAB *tab, POS
   table->null_row=0;
   table->status=STATUS_NO_RECORD;
 
-  trace_array->add_str(table->alias); /// @todo add info about findings below
   if (tab->type == JT_SYSTEM)
   {
     if ((error=join_read_system(tab)))

=== modified file 'sql/sql_test.cc'
--- a/sql/sql_test.cc	2010-10-21 13:03:30 +0000
+++ b/sql/sql_test.cc	2010-11-24 18:54:26 +0000
@@ -268,7 +268,7 @@ static void print_keyuse(Opt_trace_conte
   DBUG_UNLOCK_FILE;
   //key_part_map keypart_map; --?? there can be several?
   sprintf(buff2, "%s.%s= %s", keyuse->table->alias, fieldname, str.ptr());
-  Opt_trace_object(trace).add_str_escaped("condition", buff2, strlen(buff2)).
+  Opt_trace_object(trace).add_utf8("condition", buff2).
     add("null_rejecting", keyuse->null_rejecting);
 }
 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2010-11-22 09:59:17 +0000
+++ b/sql/sql_update.cc	2010-11-24 18:54:26 +0000
@@ -343,9 +343,7 @@ int mysql_update(THD *thd,
 
   { // Enter scope for optimizer trace wrapper
     Opt_trace_object wrapper(thd->opt_trace);
-    wrapper.add_str("database", table_list->db,
-                    strlen(table_list->db)).
-      add_str("table", table_list->alias, strlen(table_list->alias));
+    wrapper.add_utf8_table(table);
 
     if (error || !limit ||
         (select && select->check_quick(thd, safe_update, limit)))

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-10-21 13:03:30 +0000
+++ b/sql/sql_view.cc	2010-12-03 15:26:41 +0000
@@ -1141,8 +1141,9 @@ bool mysql_make_view(THD *thd, File_pars
 
   Opt_trace_object trace_wrapper(thd->opt_trace);
   Opt_trace_object trace_view(thd->opt_trace, "view");
-  trace_view.add_str("db", table->db, table->db_length).
-    add_str("name", table->table_name, table->table_name_length).
+  // When reading I_S.VIEWS, table->alias may be NULL
+  trace_view.add_utf8("database", table->db, table->db_length).
+    add_utf8("view", table->alias ? table->alias : table->table_name).
     add("in_select#", old_lex->select_lex.select_number);
 
   /*

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2010-11-17 12:27:39 +0000
+++ b/sql/sys_vars.cc	2010-11-23 10:21:53 +0000
@@ -1425,11 +1425,15 @@ static Sys_var_flagset Sys_optimizer_tra
        Opt_trace_context::flag_names,
        DEFAULT(Opt_trace_context::FLAG_DEFAULT));
 
+/*
+  Note how "misc" is not here: it is not accessible to the user; disabling
+  "misc" disables the top object which makes an empty trace.
+*/
 static Sys_var_flagset Sys_optimizer_trace_features(
        "optimizer_trace_features",
        "Enables/disables tracing of selected features of the Optimizer:"
        " optimizer_trace_features=option=val[,option=val...], where option is one of"
-       " {misc, greedy_search, range_optimizer}"
+       " {greedy_search, range_optimizer}"
        " and val is one of {on, off, default}",
        SESSION_VAR(optimizer_trace_features), CMD_LINE(REQUIRED_ARG),
        Opt_trace_context::feature_names,

=== modified file 'unittest/gunit/opt_trace-t.cc'
--- a/unittest/gunit/opt_trace-t.cc	2010-10-21 20:24:51 +0000
+++ b/unittest/gunit/opt_trace-t.cc	2010-11-24 18:54:26 +0000
@@ -29,8 +29,41 @@
 CHARSET_INFO *system_charset_info= &my_charset_utf8_general_ci;
 /* ... end here. */
 
-const Opt_trace_context::feature_value all_features=
-  Opt_trace_context::FEATURES_DEFAULT;
+const ulonglong all_features= Opt_trace_context::FEATURES_DEFAULT;
+
+
+/**
+   Checks compliance of a trace with JSON syntax rules.
+   This is a helper which has interest only when developing the test; once you
+   know that the produced trace is compliant and has expected content, just set
+   "expected" to it, add a comparison with "expected", and don't use this
+   function.
+   @param  str     pointer to trace
+   @param  length  trace's length
+*/
+void check_json_compliance(const char *str, size_t length)
+{
+#if 0
+  /*
+    Read from stdin, eliminate comments, parse as JSON. If invalid, an exception
+    is thrown by Python, uncaught, which produces a non-zero error code.
+  */
+  const char python_cmd[]=
+    "python -c \""
+    "import json, re, sys;"
+    "s= sys.stdin.read();"
+    "s= re.sub('/\\\\*[ A-Za-z_]* \\\\*/', '', s);"
+    "json.loads(s, 'utf-8')\"";
+  // Send the trace to this new process' stdin:
+  FILE *fd= popen(python_cmd, "w");
+  ASSERT_NE((void*)NULL, fd);
+  ASSERT_EQ((size_t)1, fwrite(str, length, 1, fd));
+  int rc= pclose(fd);
+  rc= WEXITSTATUS(rc);
+  ASSERT_EQ(0, rc);
+#endif
+}
+
 
 /** Test empty trace */
 TEST(Trace_content_test, empty)
@@ -55,6 +88,7 @@ TEST(Trace_content_test, empty)
   const char expected[]= "{\n}";
   ASSERT_STREQ(expected, info.trace_ptr);
   ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
   ASSERT_EQ((size_t)0, info.missing_bytes);
   ASSERT_EQ(false, info.malloc_error);
   /* Should be no more traces */
@@ -76,11 +110,11 @@ TEST(Trace_content_test, normal_usage)
       ota.add(200.4);
       {
         Opt_trace_object oto1(&trace);
-        oto1.add_str("one key", "one value").
+        oto1.add_alnum("one key", "one value").
           add("another key", 100U);
       }
       Opt_trace_context *trace_ptr= &trace;
-      OPT_TRACE(trace_ptr, add_str("one string element"));
+      OPT_TRACE(trace_ptr, add_alnum("one string element"));
       ota.add(true);
     }
     oto.add("yet another key", -1000LL);
@@ -114,6 +148,7 @@ TEST(Trace_content_test, normal_usage)
     "}";
   ASSERT_STREQ(expected, info.trace_ptr);
   ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
   ASSERT_EQ((size_t)0, info.missing_bytes);
   ASSERT_EQ(false, info.malloc_error);
   it++;
@@ -137,10 +172,10 @@ TEST(Trace_content_test, tail)
       ota.add(200.4);
       {
         Opt_trace_object oto1(&trace);
-        oto1.add_str("one key", "one value").
+        oto1.add_utf8("one key", "one value", 7). // test explicit length
           add("another key", 100LL);
       }
-      ota.add_str("one string element");
+      ota.add_utf8("one string element", 15);    // test explicit length
       ota.add(true);
     }
     oto.add("yet another key", -1000LL);
@@ -159,10 +194,10 @@ TEST(Trace_content_test, tail)
     "  \"one array\": [\n"
     "    200.4,\n"
     "    {\n"
-    "      \"one key\": \"one value\",\n"
+    "      \"one key\": \"one val\",\n"
     "      \"another key\": 100\n"
     "    },\n"
-    "    \"one string element\",\n"
+    "    \"one string elem\",\n"
     "    true\n"
     "  ] /* one array */,\n"
     "  \"yet another key\": -1000,\n"
@@ -199,10 +234,10 @@ TEST(Trace_content_test, buggy_object)
       {
         Opt_trace_object oto1(&trace);
         Opt_trace_struct::dbug_assert_on_syntax_error= false;
-        oto1.add_str("one value"); // no key, which is wrong
+        oto1.add_alnum("one value"); // no key, which is wrong
         Opt_trace_struct::dbug_assert_on_syntax_error= true;
       }
-      ota.add_str("one string element");
+      ota.add_alnum("one string element");
       ota.add(true);
     }
     oto.add("yet another key", -1000LL);
@@ -301,7 +336,7 @@ TEST(Trace_content_test, disable_I_S)
       ota.add(200.4);
       {
         Opt_trace_object oto1(&trace);
-        oto1.add_str("one key", "one value").
+        oto1.add_alnum("one key", "one value").
           add("another key", 100LL);
         Opt_trace_disable_I_S otd(&trace, true);
         oto1.add("a third key", false);
@@ -313,7 +348,7 @@ TEST(Trace_content_test, disable_I_S)
         oto2.add("another key inside", 5LL);
       }
       Opt_trace_context *trace_ptr= &trace;
-      OPT_TRACE(trace_ptr, add_str("one string element"));
+      OPT_TRACE(trace_ptr, add_alnum("one string element"));
       ota.add(true);
     }
     Opt_trace_disable_I_S otd2(&trace, false); // don't disable
@@ -348,6 +383,7 @@ TEST(Trace_content_test, disable_I_S)
     "}";
   ASSERT_STREQ(expected, info.trace_ptr);
   ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
   ASSERT_EQ((size_t)0, info.missing_bytes);
   ASSERT_EQ(false, info.malloc_error);
   it++;
@@ -467,7 +503,7 @@ TEST(Trace_settings_test, max_mem_size)
     Opt_trace_array ota(&trace, "one array");
     for (int i= 0; i < 100; i++)
     {
-      ota.add_str("make it long");
+      ota.add_alnum("make it long");
     }
   }
   trace.end();
@@ -503,14 +539,14 @@ TEST(Trace_settings_test, max_mem_size2)
   /* make a "long" trace */
   {
     Opt_trace_object oto(&trace);
-    oto.add_str("some key1", "make it long");
+    oto.add_alnum("some key1", "make it long");
   }
   trace.end();
   /* A second similar trace */
   ASSERT_EQ(false, trace.start(true, false, false, -2, 2, 21, all_features));
   {
     Opt_trace_object oto(&trace);
-    oto.add_str("some key2", "make it long");
+    oto.add_alnum("some key2", "make it long");
   }
   trace.end();
   Opt_trace_iterator it(&trace);
@@ -534,7 +570,7 @@ TEST(Trace_settings_test, max_mem_size2)
   ASSERT_EQ(false, trace.start(true, false, false, -2, 2, 21, all_features));
   {
     Opt_trace_object oto(&trace);
-    oto.add_str("some key3", "make it long");
+    oto.add_alnum("some key3", "make it long");
   }
   trace.end();
   Opt_trace_iterator it2(&trace);
@@ -606,7 +642,7 @@ TEST(Trace_content_test, filtering_by_fe
       ota.add(200.4);
       {
         Opt_trace_object oto1(&trace, Opt_trace_context::GREEDY_SEARCH);
-        oto1.add_str("one key", "one value").
+        oto1.add_alnum("one key", "one value").
           add("another key", 100LL);
         Opt_trace_object oto2(&trace, "a fourth key",
                               Opt_trace_context::MISC);
@@ -647,8 +683,113 @@ TEST(Trace_content_test, filtering_by_fe
     "}";
   ASSERT_STREQ(expected, info.trace_ptr);
   ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
+  ASSERT_EQ((size_t)0, info.missing_bytes);
+  ASSERT_EQ(false, info.malloc_error);
+  it++;
+  ASSERT_EQ(false, it != Opt_trace_iterator::end);
+}
+
+
+/** Test escaping of characters */
+TEST(Trace_content_test, escaping)
+{
+  Opt_trace_context trace;
+  ASSERT_EQ(false, trace.start(true, true, false, -1, 1, ULONG_MAX,
+                               all_features));
+  // All ASCII 0-127 chars are valid UTF8 encodings
+  char all_chars[130];
+  for (uint c= 0; c < sizeof(all_chars) - 2 ; c++)
+    all_chars[c]= c;
+  // Now a character with a two-byte code in utf8: ä
+  all_chars[128]= 0xc3;
+  all_chars[129]= 0xa4;
+  // all_chars is used both as query...
+  trace.set_query(all_chars, sizeof(all_chars), system_charset_info);
+  {
+    Opt_trace_object oto(&trace);
+    // ... and inside the trace:
+    oto.add_utf8("somekey", all_chars, sizeof(all_chars));
+  }
+  trace.end();
+  Opt_trace_iterator it(&trace);
+  ASSERT_EQ(true, it != Opt_trace_iterator::end);
+  const Opt_trace_info info= *it;
+  // we get the trace escaped, JSON-compliant:
+  const char expected[]=
+    "{\n"
+    "  \"somekey\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\t\\n\\u000b\\u000c\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ä\"\n"
+    "}";
+  ASSERT_STREQ(expected, info.trace_ptr);
+  ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
+  ASSERT_EQ((size_t)0, info.missing_bytes);
+  ASSERT_EQ(false, info.malloc_error);
+  ASSERT_EQ(sizeof(all_chars), info.query_length);
+  // we get the query unescaped, verbatim, not 0-terminated:
+  ASSERT_EQ(0, memcmp(all_chars, info.query_ptr, sizeof(all_chars)));
+  ASSERT_EQ(system_charset_info, info.query_charset);
+  it++;
+  ASSERT_EQ(false, it != Opt_trace_iterator::end);
+}
+
+
+/** Test how the system handles non-UTF8 characters, a violation of its API */
+TEST(Trace_content_test, non_utf8)
+{
+  Opt_trace_context trace;
+  ASSERT_EQ(false, trace.start(true, true, false, -1, 1, ULONG_MAX,
+                               all_features));
+  /*
+    A string which starts with invalid utf8 (the four first bytes are éèÄà in
+    latin1).
+    In utf8, the following holds
+    - E0->EF can only be the start of a 3-byte sequence
+    - C2->DF                            2-byte
+    - ASCII              a single-byte sequence
+    Because the query was declared as latin1, the trace system takes the
+    precaution to search for and eliminate any non-utf8 characters in the trace
+    (which should not exist, as they violate the API as add_utf8()
+    requires utf8). We test this here.
+    Given the utf8 rules above, the string below is filtered like this:
+    - \xe9 is in E0-EF so is the start of 3-byte sequence, so \xe8 should be
+    the second byte, but \xe8 is also in E0-EF thus the start of a 3-byte
+    sequence: so we have invalid utf8 and \xe9 is replaced with '?', and we
+    restart from \xe8
+    - \xe8 is in E0-EF so start of 3-byte sequence, so \xc4 should be second
+    byte, but is in C2-DF so is start of 2-byte sequence: invalid, \xe8 is
+    replaced with '?'
+    - \xc4 is in C2-DF, so start of a 2-byte sequence, so \xe0 should be second
+    byte, but is in E0-EF so is start of 3-byte sequence: invalid, \xc4 is
+    replaced with '?'
+    - \xe0 is in E0-EF so start of 3-byte sequence so 'A' should be second, but
+   is ASCII so is single-byte sequence: invalid, \xe0 is replaced with '?'
+   - 'A' 'B' and 'C' are valid utf8 and preserved.
+  */
+  const char all_chars[]= "\xe9\xe8\xc4\xe0" "ABC";
+  // We declare a query in latin1
+  trace.set_query(all_chars, sizeof(all_chars), &my_charset_latin1);
+  {
+    Opt_trace_object oto(&trace);
+    oto.add_utf8("somekey", all_chars, sizeof(all_chars) - 1);
+  }
+  trace.end();
+  Opt_trace_iterator it(&trace);
+  ASSERT_EQ(true, it != Opt_trace_iterator::end);
+  const Opt_trace_info info= *it;
+  // This is UTF8 and thus JSON-compliant; ABC is present
+  const char expected[]=
+    "{\n"
+    "  \"somekey\": \"????ABC\"\n"
+    "}";
+  ASSERT_STREQ(expected, info.trace_ptr);
+  ASSERT_EQ(sizeof(expected) - 1, info.trace_length);
+  check_json_compliance(info.trace_ptr, info.trace_length);
   ASSERT_EQ((size_t)0, info.missing_bytes);
   ASSERT_EQ(false, info.malloc_error);
+  ASSERT_EQ(sizeof(all_chars), info.query_length);
+  // we get the query unescaped, verbatim, not 0-terminated:
+  ASSERT_EQ(0, memcmp(all_chars, info.query_ptr, sizeof(all_chars)));
   it++;
   ASSERT_EQ(false, it != Opt_trace_iterator::end);
 }

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-next-mr-bugfixing branch (jorgen.loland:3234 to 3242)WL#4800Jorgen Loland21 Dec