#At file:///home/mysql_src/bzrrepos_new/mysql-next-mr-opt-backporting-wl4800/ based on revid:guilhem.bichot@oracle.com-20110414130222-8arv4703gu38zi1j
3296 Guilhem Bichot 2011-05-04
Security patch for optimizer trace.
Behaviour changes:
1)
[ suggested background: http://dev.mysql.com/doc/refman/5.5/en/stored-programs-security.html ]
Definition of "connected user":
== the one which opened the connection; <> some SUID user of SQL SECURITY DEFINER objects.
The idea is that the query's trace exposes more information than the query's result set,
including information which the connected user has no privilege to see;
we must prevent the connected user from seeing this information. We do
it with several measures.
1.1) when using base table or view: disable tracing if connected user doesn't have table-level SELECT
privilege on base table.
1.2) when using view: disable tracing if connected user doesn't have SHOW VIEW privilege on view or
doesn't have SELECT privilege on underlying base tables or view (same tests as EXPLAIN already does).
1.3) when using routine: disable tracing if connected user doesn't have privileges to see
routine's body.
1.4) when using object which has a security context (view, routine): disable tracing if
this context's user is different from connected user, unless connected user has all
privileges.
1.5) when reading I_S.OPTIMIZER_TRACE, return an empty result set if the
current security context is different from the connected user, unless
the current security context has all privileges.
"Disable tracing" here means: flag the current statement's trace as "missing a privilege"
(so in I_S.OPTIMIZER_TRACE the trace will appear as empty and the
INSUFFICIENT_PRIVILEGES column will be "1"), and recursively disable tracing
for all children substatements of this statement (they won't even have a row
in I_S.OPTIMIZER_TRACE, to not expose the number of substatements).
Implementation of all changes above is done in those steps:
1.10) new security-checking functions called each time we start a statement using
some base tables or views, execute a routine, open a view.
1.11) those checks are always done unless @@optimizer_trace has "enabled=off";
in particular, they are done even though the statement is outside
the @@optimizer_trace_offset/limit window.
1.12) a function to disable tracing existed:
Opt_trace_stmt::disable_I_S_for_this_and_children();
it had two problems: it could fail if OOM, and it required an Opt_trace_stmt.
There can now be cases where we want to disable tracing recursively
even though the current statement has no trace, or even though Opt_trace_context
hasn't been allocated. Thus:
1.12.1) Opt_trace_context is split in two pieces: most of it moves to
Opt_trace_context_impl, dynamically allocated; a small piece (a counter and
a pointer to Opt_trace_context_impl) is left in Opt_trace_context,
and THD now contains an Opt_trace_context object instead of a pointer.
1.12.2) the counter in Opt_trace_context serves to keep the value
of "I_S support for any to-be-created traces" (0 means they should
support I_S):
1.12.2.1) disable_I_S_for_this_and_children() increments it (affects the to-be-created traces)
and tells the current statement to disable its own I_S output (affects the current statement)
1.12.2.2) restore_I_S() does opposite operations.
1.12.3) As I_S support for to-be-created traces and for the current trace are now
in two different variables, I_S support for the current trace is just
a yes/no variable (3rd value NO_FOR_THIS_AND_CHILDREN is gone), thus
it (Opt_trace_stmt::support_I_S) is changed from enum_support_I_S to boolean
1.12.4) Opt_trace_stmt::support_I_S used to vary as we enter and leave Opt_trace_struct
objects, due to tracable and non-tracable features like greedy search; we used
to keep track of this in a stack of successive values of Opt_trace_stmt::support_I_S;
but as disabling I_S in an Opt_trace_struct keeps I_S output disabled
until leaving this struct, it is possible to change Opt_trace_stmt::support_I_S
to be a counter (0 means I_S output is enabled); this eliminates a stack,
its memory consumption and possible OOM failure.
1.12.5) argument 'support_I_S' to constructor of Opt_trace_stmt is deleted,
instead, creator of the object just calls
Opt_trace_stmt::disable_I_S() on the new object
1.13) a function to set the "missing privilege" mark for current statement is added:
Opt_trace_context::missing_privilege(); it sets the mark, disables I_S output for
future children substatements; I_S output is re-enabled when current statement
ends.
1.14) that function requires an Opt_trace_stmt (which is where we store
that I_S output should be re-enabled when statement ends); dbug output
has the same requirement; thus an argument 'support_dbug_or_support_missing_priv'
is added to Opt_trace_context::start(); if it's true we must create an Opt_trace_stmt;
this also simplifies logic in opt_trace_start().
1.15) a RAII class "Opt_trace_start", replacing opt_trace_start()/opt_trace_end(),
is added; it simplifies code in sql_parse.cc, sql_prepare.cc.
Other behaviour changes, inspired by review discussions:
2) in routines, we now also trace statements which are not basic SQL but
still can manipulate subqueries: DECLARE, IF, CASE, RETURN; without that,
in "IF(subq) THEN ...", subquery was not traced.
3) when a command is not traced because
sql_command_can_be_traced() returns 'false',
we used to disable tracing of its substatements, this is not the case anymore.
Thus we don't need to trace SQL PREPARE and SQL EXECUTE (which
always produced uninteresting traces), only need to trace their prepared or executed
statement. Additional benefit: now SQL PREPARE and SQL EXECUTE
produce one trace each, which is what the C API mysql_stmt_prepare() and
mysql_stmt_execute() calls already did, so it's consistent.
@ WL4800_TODO.txt
questions for reviewers. Organized the todo in sections.
@ WL4800_validate_json.py
ability to handle several ".result" files in one command line
@ mysql-test/include/optimizer_trace.inc
change (2) influences number of seen traces.
@ mysql-test/include/optimizer_trace2.inc
test changes (3) and (2).
Test that subquery used in parameter of routine call, is traced.
@ mysql-test/include/optimizer_trace_security.inc
test change (1): different scenarios of tables/views/triggers/routines,
to verify that the user sees only what he should.
@ mysql-test/r/optimizer_trace2_no_prot.result
effects of (2): more traces in routines. test changes (3) and (2).
@ mysql-test/r/optimizer_trace2_ps_prot.result
effects of (2): more traces in routines. test changes (3) and (2).
@ mysql-test/r/optimizer_trace_no_prot.result
new column INSUFFICIENT_PRIVILEGES. Change (2) influences number of seen traces.
@ mysql-test/r/optimizer_trace_ps_prot.result
new column INSUFFICIENT_PRIVILEGES. Change (2) influences number of seen traces.
@ mysql-test/r/optimizer_trace_range_no_prot.result
new column INSUFFICIENT_PRIVILEGES
@ mysql-test/r/optimizer_trace_range_ps_prot.result
new column INSUFFICIENT_PRIVILEGES
@ mysql-test/r/optimizer_trace_subquery_no_prot.result
new column INSUFFICIENT_PRIVILEGES
@ mysql-test/r/optimizer_trace_subquery_ps_prot.result
new column INSUFFICIENT_PRIVILEGES
@ mysql-test/suite/funcs_1/r/is_columns_is.result
fix for a rarely run test...
@ mysql-test/t/optimizer_trace_bugs.test
empty test, deleted
@ mysql-test/t/optimizer_trace_debug.test
Opt_trace_stmt is created more often now, for example in
set optimizer_trace="enabled=on";
select * from information_schema.OPTIMIZER_TRACE; # here
so test is adjusted.
We test that the case which is important to optimize (i.e. "enabled=off")
is still optimized.
@ sql/item_subselect.cc
THD::opt_trace is object now, not pointer
@ sql/mysqld.cc
THD::opt_trace is object now, not pointer
@ sql/opt_range.cc
THD::opt_trace is object now, not pointer
@ sql/opt_trace.cc
review comment: moving Buffer out of Opt_trace_stmt.
Implementation of changes 1.12), 1.13), 1.14)
@ sql/opt_trace.h
Implementation of changes 1.12), 1.13), 1.14), 1.15).
One @todo is deleted, things which we don't trace yet are for later WLs, already created.
@ sql/opt_trace2server.cc
Implementation of changes 1.1), 1.2), 1.3), 1.4), 1.5), 1.10), 1.11), 1.15), 3).
@ sql/sp_head.cc
Implementation of changes 1.10) and 2).
Removing sp_instr::exec_open_and_lock_tables() and shuffling code
was ok'd with DmitryL.
@ sql/sql_class.cc
THD::opt_trace is object now, not pointer
@ sql/sql_class.h
THD::opt_trace is object now, not pointer
@ sql/sql_delete.cc
THD::opt_trace is object now, not pointer
@ sql/sql_help.cc
THD::opt_trace is object now, not pointer
@ sql/sql_parse.cc
Per change (2), SQLCOM_EXECUTE/PREPARE don't need flag CF_OPTIMIZER_TRACE.
Use of Opt_trace_start (change 1.15) allows not using Opt_trace_struct::end()
functions (thanks to order of destructor calls), and allows
the caller to not keep a local 'started_optimizer_trace' bool.
@ sql/sql_prepare.cc
Use of Opt_trace_start (change 1.15) allows not using end()
functions (thanks to order of destructor calls), and allows
the caller to not keep a local started_optimizer_trace bool.
Thus some code is reverted to what it is in trunk.
@ sql/sql_select.cc
THD::opt_trace is object now, not pointer. One @todo is deleted,
things which we don't trace yet are for later WLs, already created.
@ sql/sql_update.cc
THD::opt_trace is object now, not pointer
@ sql/sql_view.cc
Implementation of change 1.10) (views)
@ sql/sys_vars.cc
THD::opt_trace is object now, not pointer
@ sql/table.cc
Implementation of change 1.10) (security context change by view)
@ unittest/gunit/opt_trace-t.cc
- test of new functions, of info.missing_priv property
- do_check_json_compliance() doesn't accept empty traces
- don't try to check JSON compliance of traces which
are known to not be in utf8
removed:
mysql-test/r/optimizer_trace_bugs.result
mysql-test/t/optimizer_trace_bugs.test
added:
mysql-test/include/optimizer_trace_security.inc
mysql-test/r/optimizer_trace_security_no_prot.result
mysql-test/r/optimizer_trace_security_ps_prot.result
mysql-test/t/optimizer_trace_security_no_prot.test
mysql-test/t/optimizer_trace_security_ps_prot.test
modified:
WL4800_TODO.txt
WL4800_validate_json.py
mysql-test/include/optimizer_trace.inc
mysql-test/include/optimizer_trace2.inc
mysql-test/r/optimizer_trace2_no_prot.result
mysql-test/r/optimizer_trace2_ps_prot.result
mysql-test/r/optimizer_trace_debug.result
mysql-test/r/optimizer_trace_no_prot.result
mysql-test/r/optimizer_trace_ps_prot.result
mysql-test/r/optimizer_trace_range_no_prot.result
mysql-test/r/optimizer_trace_range_ps_prot.result
mysql-test/r/optimizer_trace_subquery_no_prot.result
mysql-test/r/optimizer_trace_subquery_ps_prot.result
mysql-test/suite/funcs_1/r/is_columns_is.result
mysql-test/t/optimizer_trace_debug.test
sql/item_subselect.cc
sql/mysqld.cc
sql/opt_range.cc
sql/opt_trace.cc
sql/opt_trace.h
sql/opt_trace2server.cc
sql/sp_head.cc
sql/sp_head.h
sql/sql_class.cc
sql/sql_class.h
sql/sql_delete.cc
sql/sql_help.cc
sql/sql_parse.cc
sql/sql_prepare.cc
sql/sql_select.cc
sql/sql_update.cc
sql/sql_view.cc
sql/sys_vars.cc
sql/table.cc
unittest/gunit/opt_trace-t.cc
=== modified file 'WL4800_TODO.txt'
--- a/WL4800_TODO.txt 2011-04-05 07:34:13 +0000
+++ b/WL4800_TODO.txt 2011-05-04 20:53:28 +0000
@@ -1,52 +1,90 @@
Short-term TODO list to remember for WL#4800
============================================
-see all added @todo
+A) TO DO BEFORE PUSH
-My command to update the HTML Doxygen is:
-rsync -avz /m/doxygen/mysql-wl4800 [URL]:public_html
+Coding style:
+Make sure long code lines are wrapped, and no trailing white space is
+added.
+
+Update copyright header of all changed files to reflect changed in 2011
+
+B) TO DO AFTER PUSH
+
+- in the manual, mention that people should dump their trace with
+SELECT INTO DUMPFILE instead of OUTFILE
+- in changelog, mention the added /*select#*/ in EXPLAIN EXTENDED; in
+the manual, mention use of this to decrypt what "id" is about in
+EXPLAIN output.
-fix bugs recorded in optimizer_trace_bugs.test and delete that test.
+C) QUESTIONS FOR REVIEWERS
-Open question: should we have a "version" property in the top trace
+C1) should we have a "version" property in the top trace
object? Assume that at some point in development there is a
significant overhaul of the trace's organization: new apps will have
to be able to parse old and new traces; would it help them to have a
version number in order to distinguish between old/new? Drawback: do
not forget to bump the version when doing certain changes (and: what
changes? any little change? maybe).
+Guilhem suggests: don't have a version.
-Coding style:
-Make sure long code lines are wrapped, and no trailing white space is
-added.
-
-Misc security issues as discussed already.
+C2) Guilhem to Jorgen: do you still want more precise checks for non-unique keys
+to be bundled in the debug binary? right now, there is a simple check
+that a key is different from the previous key; and there are full
+checks if one uses WL4800_validate_json.py.
-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?
-
-The optimizer may have second thoughts about which access method to
+C3) Jorgen wrote: 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;
+Guilhem asks: Can we fix this before push? If not, how to handle it?
-Make --opt-trace-protocol dump traces to a separate file so that mtr
+C4) Jorgen wrote: Make --opt-trace-protocol dump traces to a separate file so that mtr
can run with it without failing all tests.
+Guilhem asks: good idea, but how much is it needed?
+--explain-protocol, --sp-protocol, --view-protocol make all tests
+fail. Maybe I can merely move this as an idea in a comment in mysqltest.cc
+near the definition of opt-trace-protocol?
-Update copyright header of all changed files to reflect changed in 2011
-
-should the debug binary really assert(0) if json syntax error? is it a
+C5) should the debug binary really assert(0) if json syntax error? is it a
good idea at the customer's? On the other hand, how to make sure a
developer notices a syntax error when running tests?
sql_print_warning() is an idea.
+Guilhem suggests: keep it as it is (assert(0))
-get a review for http://lists.mysql.com/commits/133482
+C6) Should mysql-test/t/optimizer_trace* move into
+mysql-test/suite/optimizer_trace ?
+Guilhem suggests: yes.
+
+C7) Dmitry advised we should trace SET and DO. Right now SET-which-sets-local-routine-vars is
+traced, but SET-which-sets-other-vars is not, this is
+inconsistent. And SET may use a subquery (SET @a=(subq)) which is
+worth tracing.
+Guilhem says: agree. A drawback of this is that
+SET optimizer_trace="enabled=off";
+will be traced, which is a nuisance, as it deletes previous trace.
+But next item below which could eliminate this drawback.
+
+C8) should we limit tracing to statements using
+tables/views? This would decrease the noise when tracing a routine
+(even DECLARE is traced now), and would nicely distinguish between
+ SET @x=(subq); # should be traced
+and
+ SET optimizer_trace="enabled=off"; # tracing is nuisance, as it
+ # deletes previous trace
+The worst consequence it could have is that
+ SELECT stored_func();
+would not be traced (but its substatements would still be, if they use
+tables/views).
+
+C9) The entire opt_trace.h is included in sql_class.h which itself is
+included everywhere. Of opt_trace.h, sql_class.h needs only
+Opt_trace_context. Should declaration of Opt_trace_context move to a
+separate smaller include file, to be included in sql_class.h?
+Guilhem suggests: yes.
-Move Buffer out of Opt_trace_stmt, in unnamed namespace in
-opt_trace.cc.
+C10) Guilhem to Tor: can we delete opt_notrace-t.cc now? I think I
+replied in some old mail about this file.
=== modified file 'WL4800_validate_json.py'
--- a/WL4800_validate_json.py 2011-02-16 15:06:06 +0000
+++ b/WL4800_validate_json.py 2011-05-04 20:53:28 +0000
@@ -19,21 +19,22 @@ import sys
usage = """
Usage:
- %s <a_file>
+ %s <a_file> <another_file> <etc>
-It will verify that all optimizer traces of a_file (usually a_file
+It will verify that all optimizer traces of files (usually a_file
is a .result or .reject file which contains
SELECT * FROM OPTIMIZER_TRACE; ) are JSON-compliant.
Exit code is 0 if all ok.
""" % sys.argv[0]
-if len(sys.argv) != 2:
+if len(sys.argv) < 2:
print usage
sys.exit(1)
import json, re
-retcode=0
+trace_start_re = re.compile("^.*(\t)?{\n")
+trace_end_re = re.compile("^}")
def check(trace, first_trace_line):
global retcode
@@ -70,28 +71,31 @@ def check(trace, first_trace_line):
return
print "ok at line", first_trace_line
-all = open(sys.argv[1]).readlines()
-trace_start_re = re.compile("^(.*\t)?{\n")
-trace_end_re = re.compile("^}")
-
-first_trace_line = trace_line = 0
-trace = None
-for l in all:
- trace_line += 1
- if trace_start_re.match(l):
- assert first_trace_line == 0
- trace = []
- first_trace_line = trace_line
- trace.append("{\n")
- continue
- if trace_end_re.match(l):
- assert first_trace_line != 0
- trace.append("}") # eliminate any following columns of table (OS_MALLOC_ERROR etc)
- check(trace, first_trace_line)
- first_trace_line = 0
- if first_trace_line != 0:
- # eliminate /* */ (not valid JSON)
- no_comment = re.sub("/\*.*\*/", "", l)
- trace.append(no_comment)
+def handle_one_file(name):
+ all = open(name).readlines()
+ first_trace_line = trace_line = 0
+ trace = None
+ for l in all:
+ trace_line += 1
+ if trace_start_re.match(l) and first_trace_line == 0:
+ trace = []
+ first_trace_line = trace_line
+ trace.append("{\n")
+ continue
+ if trace_end_re.match(l):
+ assert first_trace_line != 0
+ trace.append("}") # eliminate any following columns of table (OS_MALLOC_ERROR etc)
+ check(trace, first_trace_line)
+ first_trace_line = 0
+ if first_trace_line != 0:
+ # eliminate /* */ (not valid JSON)
+ no_comment = re.sub("/\*.*\*/", "", l)
+ trace.append(no_comment)
+retcode=0
+for f in sys.argv[1:]:
+ print "FILE %s" % f
+ print
+ handle_one_file(f)
+ print
sys.exit(retcode)
=== modified file 'mysql-test/include/optimizer_trace.inc'
--- a/mysql-test/include/optimizer_trace.inc 2011-02-15 20:53:19 +0000
+++ b/mysql-test/include/optimizer_trace.inc 2011-05-04 20:53:28 +0000
@@ -381,44 +381,42 @@ begin
return ret;
end|
select f1()|
-# Here we will see the trace of SELECT SUM etc;
-# if this SELECT SUM had been the argument of RETURN,
-# SP code would treat it as an expression and not a statement,
-# thus mysql_execute_command() would not be called, thus
-# the trace would rather show DELETE.
+# Here we will see the trace of RETURN.
select * from information_schema.OPTIMIZER_TRACE|
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; this means 7 traces:
+# Want to see the top and invoked sub-statements; this means 11 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|
+# in the stored function we have traces: DECLARE (1 trace), 3 DMLs
+# and RETURN (1 trace). 1+2*(1+3+1)=11.
+# In ps-protocol mode, we have those 11, plus one for PREPARE of the
+# top SELECT.
+# We ask for a larger number (20) and will check how many we got.
+set optimizer_trace_offset=-20, optimizer_trace_limit=20|
select * from t6 where d in (select f1() from t2 where s="c")|
select * from information_schema.OPTIMIZER_TRACE|
+select count(*) from information_schema.OPTIMIZER_TRACE|
# Want to see the DELETE (invoked sub-statement):
-set optimizer_trace_offset=2, optimizer_trace_limit=1|
+set optimizer_trace_offset=3, 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.
+# In ps-protocol mode, we also have trace of PREPARE for the top
+# SELECT, so we see one trace before the DELETE: the INSERT.
select * from information_schema.OPTIMIZER_TRACE|
-set optimizer_trace_offset=default, optimizer_trace_limit=default|
# Stored procedures
-
create procedure p1(arg char(1))
begin
declare res int;
select d into res from t6 where d in (select f1() from t2 where s=arg);
select d+1 into res from t6 where d=res+1;
end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
call p1("c")|
select * from information_schema.OPTIMIZER_TRACE|
@@ -427,28 +425,30 @@ create trigger trg1 before insert on t2
begin
set new.s=f1();
end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100|
insert into t2 select d,100,200 from t6 where d is not null|
select * from information_schema.OPTIMIZER_TRACE|
select * from t2|
-
delimiter ;|
# PREPARE/EXECUTE/EXECUTE
-prepare stmt from 'call p1(?)';
-select QUERY from information_schema.OPTIMIZER_TRACE;
+prepare stmt from 'select count(*) from t1 where t1.data=?';
set @param="c";
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
+select count(*) from information_schema.OPTIMIZER_TRACE;
select TRACE into @trace from information_schema.OPTIMIZER_TRACE;
select @trace;
# second EXECUTE should give same trace
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
+select count(*) from information_schema.OPTIMIZER_TRACE;
select TRACE into @trace2 from information_schema.OPTIMIZER_TRACE;
select @trace=@trace2;
-
# enable/disable tracing in middle of procedure
drop procedure p1;
-create table optt like information_schema.OPTIMIZER_TRACE;
+create temporary table optt like information_schema.OPTIMIZER_TRACE;
delimiter |;
create procedure p1(arg char(1))
begin
@@ -469,7 +469,7 @@ select @@optimizer_trace|
delimiter ;|
set optimizer_trace="enabled=on";
-drop table optt;
+drop temporary table optt;
drop function f1;
drop procedure p1;
drop trigger trg1;
=== modified file 'mysql-test/include/optimizer_trace2.inc'
--- a/mysql-test/include/optimizer_trace2.inc 2011-04-13 15:36:01 +0000
+++ b/mysql-test/include/optimizer_trace2.inc 2011-05-04 20:53:28 +0000
@@ -18,6 +18,8 @@ begin
select 2 into res from dual;
return 3;
end|
+# ps-protocol specific note: as we asked to retain all traces,
+# we see the one of PREPARE too.
select f1("c")|
--echo
# we should not see the trace of "select TRACE+NULL..."
@@ -187,8 +189,7 @@ SELECT POLYGON((SELECT 1 FROM (SELECT 1
DROP TABLE t1;
--echo
---echo # Check that SQL PREPARE produces one statement, and
---echo # check that SQL EXECUTE produces two
+--echo # Check that SQL PREPARE and SQL EXECUTE each produce one trace.
--echo
set optimizer_trace_offset=0, optimizer_trace_limit=100;
prepare stmt from "select 1";
@@ -200,11 +201,7 @@ deallocate prepare stmt;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
--echo
---echo # Test of SELECTs in IF in stored routine. IF is not a real
---echo # command: not in enum_sql_command, does not have a dedicated
---echo # call to mysql_execute_command() for it; IF rather executes as
---echo # a part of the routine's call (CALL, for a procedure). It is
---echo # thus traced or not, as the routine's call.
+--echo # Test of SELECTs in IF in stored routine.
--echo # Same test for CASE WHEN.
--echo
create table t1 (a int);
@@ -228,15 +225,55 @@ begin
end|
delimiter ;|
set optimizer_trace_offset=0, optimizer_trace_limit=100;
+set optimizer_trace_max_mem_size=20000;
call p1();
-# IF EXISTS() are traced because part of CALL,
-# same for first IF (SELECT) and for
-# CASE (SELECT).
# SET @a=(SELECT) is not traced because part of SET
# which is a real command and not traced.
select * from information_schema.OPTIMIZER_TRACE;
select * from t1;
select @a,@b;
+set optimizer_trace_max_mem_size=default;
+drop procedure p1;
+drop table t1;
+
+--echo
+--echo # Test that in a non-traced SQL command, substatements can be
+--echo # traced
+--echo
+
+create table t1(a int);
+insert into t1 values(1),(2);
+delimiter |;
+create function f1() returns int
+begin
+ declare b int;
+ select 48 into b from dual;
+ select a into b from t1 limit 1;
+ insert into t1 values(b*10);
+ return 36;
+end|
+delimiter ;|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+do f1(); # DO is never traced
+select * from information_schema.OPTIMIZER_TRACE;
+drop function f1;
+drop table t1;
+
+--echo
+--echo # Test of tracing of subquery used in parameter of routine call
+--echo
+create table t1(a int);
+insert into t1 values(1),(2);
+delimiter |;
+create procedure p1(x int)
+begin
+ declare b int;
+ set b=(select 2+x from dual);
+end|
+delimiter ;|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+call p1((select a from t1 limit 1));
+select * from information_schema.OPTIMIZER_TRACE;
drop procedure p1;
drop table t1;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
=== added file 'mysql-test/include/optimizer_trace_security.inc'
--- a/mysql-test/include/optimizer_trace_security.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/include/optimizer_trace_security.inc 2011-05-04 20:53:28 +0000
@@ -0,0 +1,739 @@
+# Test that trace does not show information forbidden
+# by lack of privileges.
+
+--source include/have_optimizer_trace.inc
+
+connection default;
+let $DEFAULT_TRACE_MEM_SIZE=1048576; # 1MB
+set @old_size = @@global.optimizer_trace_max_mem_size;
+eval set global optimizer_trace_max_mem_size=$DEFAULT_TRACE_MEM_SIZE;
+
+connection default;
+select user();
+create database somedb;
+use somedb;
+create table t1(a varchar(100));
+insert into t1 values("first");
+create table t2(a varchar(100));
+insert into t2 values("first");
+create table t3(a varchar(100));
+insert into t3 values("first");
+delimiter |;
+create procedure p1() sql security definer
+begin
+ declare b int;
+ if (select count(*) from t1)
+ then
+ select 22 into b from dual;
+ end if;
+ select a into b from t1 limit 1;
+ insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+ declare b int;
+ select 48 into b from dual;
+ select a into b from t1 limit 1;
+ insert into t1 values(current_user());
+ return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+ insert into t3 select * from t3;
+end|
+delimiter ;|
+create sql security definer view v1 as select * from t1;
+create user user1@localhost identified by '';
+grant all on *.* to user1@localhost with grant option;
+connect (con_user1, localhost, user1,, somedb);
+
+--echo
+connection con_user1;
+select user();
+set optimizer_trace="enabled=on";
+show grants;
+
+--echo
+--echo # ==========================================================
+--echo # Part A.
+--echo # Test that security context changes are allowed when, and only
+--echo # when, invoker has all global privileges.
+--echo # ==========================================================
+--echo
+
+--echo # Because invoker has all global privileges, all traces are visible:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # this SET always purges all remembered traces
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # Show that really all global privileges are needed: let root
+--echo # revoke just one from user1. Because user1 does not have all global
+--echo # privileges anymore, security context changes are forbidden,
+--echo # thus there is no trace.
+--echo
+
+connection default;
+select user();
+revoke shutdown on *.* from user1@localhost;
+# removing a global privilege never affects an existing connection:
+disconnect con_user1;
+connect (con_user1, localhost, user1,, somedb);
+
+--echo
+connection con_user1;
+select user();
+set optimizer_trace="enabled=on";
+show grants;
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+--echo # In CALL we execute stored procedure and notice a security
+--echo # context change. The context change is probably only relevant
+--echo # for substatements, but we still hide CALL. This is to be
+--echo # consistent with what we do when routine body should not be
+--echo # exposed. And it also feels safer to disable I_S output as
+--echo # soon as possible.
+--echo # Ps-protocol-specific note: mysqltest uses normal protocol for CALL
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # Verify that user1 cannot circumvent security checks by
+--echo # setting @@optimizer_trace_offset so that I_S output is disabled
+--echo # before the object (routine) is checked, and enabled in the
+--echo # middle of object usage, when 'offset' is passed.
+--echo
+
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+--echo # Even though the routine's execution started before
+--echo # 'offset', it detected the security context changes. So the
+--echo # trace of CALL gets the "missing privilege" mark but we don't
+--echo # see it as CALL was before 'offset'.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # Finally, verify that if the routine's definer does modify
+--echo # @@optimizer_trace from "enabled=off" to "enabled=on", in the
+--echo # body of the routine, then tracing works. This is no security
+--echo # issue, as it was done by the routine's definer.
+--echo
+
+connection default;
+select user();
+delimiter |;
+create procedure p2() sql security definer
+begin
+ declare b int;
+ set optimizer_trace="enabled=on";
+ select 22 into b from dual;
+end|
+delimiter ;|
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Variable is as set by the routine
+select @@optimizer_trace;
+
+--echo
+--echo # ==========================================================
+--echo # Part B.
+--echo # Do same tests but with SQL SECURITY INVOKER objects, to verify that
+--echo # the restriction on security context changes is not present.
+--echo # ==========================================================
+--echo
+
+connection default;
+select user();
+alter procedure p1 sql security invoker;
+alter function f1 sql security invoker;
+alter sql security invoker view v1 as select * from t1;
+--echo # Triggers cannot be SQL SECURITY INVOKER so we don't test
+--echo # them here.
+alter procedure p2 sql security invoker;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+--echo # SELECT substatement is traced (no security context change)
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+select @@optimizer_trace;
+
+--echo
+--echo # ==========================================================
+--echo # Part C.
+--echo # User1 got traces. Determine the minimum set of privileges he
+--echo # needed for that.
+--echo # ==========================================================
+--echo
+
+connection default;
+drop procedure p2; # p2 is not worth testing more
+select user();
+revoke all privileges, grant option from user1@localhost;
+--echo # Grant minimum privileges to use the routines and views,
+--echo # without considering optimizer trace:
+grant execute on procedure p1 to user1@localhost;
+grant execute on function f1 to user1@localhost;
+grant select (a) on v1 to user1@localhost;
+--echo # Objects above are SQL SECURITY INVOKER, so invoker needs
+--echo # privileges on objects used internally:
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+disconnect con_user1;
+connect (con_user1, localhost, user1,, somedb);
+
+--echo
+connection con_user1;
+select user();
+set optimizer_trace="enabled=on";
+show grants;
+
+--echo
+--echo # Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+--echo # In CALL we execute stored procedure and notice that body should
+--echo # not be exposed. The trace of this CALL would not expose the
+--echo # body. Trace of substatements would. But, due to
+--echo # implementation, CALL is hidden.
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+--echo # SELECT is hidden (same reason as for CALL).
+--echo # Ps-protocol-specific note: preparation of SELECT above does not
+--echo # execute f1, so does not risk exposing body, so its trace is
+--echo # visible.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it would expose body of view
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # C.0) Add more privileges:
+--echo
+
+connection default;
+select user();
+--echo # - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+--echo # - for use of routines:
+grant select on mysql.proc to user1@localhost;
+--echo # - for use of view:
+grant select, show view on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of routine, and content of t1, which we
+--echo # could see anyway:
+show create procedure p1;
+select * from t1 limit 1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of routine, and content of t1, which we
+--echo # could see anyway:
+show create function f1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of view, and content of t1, which we
+--echo # could see anyway:
+show create view v1;
+
+--echo
+--echo # Now remove each privilege to verify that it was needed:
+--echo # C.1) remove table-level SELECT privilege on t1
+--echo
+connection default;
+select user();
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+--echo # Cannot see those substatements which use t1
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+--echo # Cannot see those substatements which use t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of routine, which we could see anyway:
+set optimizer_trace="enabled=off";
+show create function f1;
+set optimizer_trace="enabled=on";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it might expose some data from columns
+--echo # of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # C.2) remove table-level SELECT privilege on mysql.proc
+--echo
+
+connection default;
+select user();
+--echo # Put back privilege removed in C.1
+grant select on t1 to user1@localhost;
+--echo # And remove a next one:
+revoke select on mysql.proc from user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+--echo # We have no right to see routines' bodies:
+set optimizer_trace="enabled=off";
+show create procedure p1;
+show create function f1;
+--echo # Verify that optimizer trace does not influence the privilege
+--echo # checking in SHOW CREATE:
+set optimizer_trace="enabled=on";
+show create procedure p1;
+show create function f1;
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+--echo # Cannot see anything as it would expose body of routine
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # C.3) remove table-level SELECT privilege on view
+--echo
+
+connection default;
+select user();
+--echo # Put back privilege removed in C.2
+grant select on mysql.proc to user1@localhost;
+--echo # And remove a next one:
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it might expose some data from columns
+--echo # of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # C.4) remove SHOW VIEW privilege on view
+--echo
+
+connection default;
+select user();
+--echo # Put back privilege removed in C.3
+grant select on v1 to user1@localhost;
+--echo # And remove a next one:
+revoke show view on v1 from user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace="enabled=off";
+--echo # We have no right to see view's body:
+--error ER_TABLEACCESS_DENIED_ERROR
+show create view v1;
+set optimizer_trace="enabled=on";
+--echo # Verify that optimizer trace does not influence the privilege
+--echo # checking in SHOW CREATE:
+--error ER_TABLEACCESS_DENIED_ERROR
+show create view v1;
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # ==========================================================
+--echo # Part D.
+--echo # Like Part C, but instead of SQL SECURITY INVOKER objects
+--echo # created by root and used by User1, let's have SQL SECURITY
+--echo # DEFINER objects created and used by User1. Determine the
+--echo # minimum set of privileges he needs for that.
+--echo # ==========================================================
+--echo
+
+connection default;
+select user();
+drop procedure p1;
+drop function f1;
+drop view v1;
+drop trigger trg2;
+revoke all privileges, grant option from user1@localhost;
+--echo # Grant minimum privileges to create and use objects,
+--echo # without considering optimizer trace:
+grant create routine on somedb.* to user1@localhost;
+grant trigger on t2 to user1@localhost;
+grant create view on somedb.* to user1@localhost;
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+grant insert (a) on t2 to user1@localhost;
+grant select (a) on t3 to user1@localhost;
+grant insert (a) on t3 to user1@localhost;
+delete from t1 where a<>"first";
+disconnect con_user1;
+connect (con_user1, localhost, user1,, somedb);
+
+--echo
+connection con_user1;
+select user();
+set optimizer_trace="enabled=on";
+
+delimiter |;
+create procedure p1() sql security definer
+begin
+ declare b int;
+ if (select count(*) from t1)
+ then
+ select 22 into b from dual;
+ end if;
+ select a into b from t1 limit 1;
+ insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+ declare b int;
+ select 48 into b from dual;
+ select a into b from t1 limit 1;
+ insert into t1 values(current_user());
+ return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+ insert into t3 select * from t3;
+end|
+delimiter ;|
+create sql security definer view v1 as select * from t1;
+
+--echo # Creating a view is not enough to be able to SELECT it...
+connection default;
+select user();
+grant select (a) on v1 to user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+--echo # Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+--echo # Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+--echo # Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+show create function f1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it might expose some data from columns
+--echo # of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+--echo # Cannot see anything as it might expose some data from
+--echo # columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Also test a query accessing t1 in FROM clause:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # D.0) Add more privileges:
+--echo
+
+connection default;
+select user();
+--echo # - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+--echo # - for use of view:
+grant select, show view on v1 to user1@localhost;
+--echo # - for use of trigger
+grant select on t2 to user1@localhost;
+grant select on t3 to user1@localhost;
+delete from t1 where a<>"first";
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of routine, and content of t1, which we
+--echo # could see anyway:
+show create procedure p1;
+select * from t1 limit 1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of routine, and content of t1, which we
+--echo # could see anyway:
+show create function f1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of view, and content of t1, which we
+--echo # could see anyway:
+show create view v1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+--echo # Trace exposed body of trigger, and content of t2/t3, which we
+--echo # could see anyway:
+show create trigger trg2;
+select * from t2, t3 limit 1;
+--echo # Trace exposed content of t1 which we could see anyway:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # For routines, as they only use t1 and we added only one
+--echo # privilege on t1, we have nothing to remove.
+--echo
+--echo # Now remove each privilege to verify that it was needed for
+--echo # the view.
+--echo # D.1) remove table-level SELECT privilege on v1
+--echo
+
+connection default;
+select user();
+
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it might expose some data from columns
+--echo # of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # D.2) remove table-level SHOW VIEW privilege on v1
+--echo
+
+connection default;
+select user();
+
+--echo # Put back privilege removed in D.1
+grant select on v1 to user1@localhost;
+--echo # And remove a next one:
+revoke show view on v1 from user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+--echo # We have no right to see view's body:
+--error ER_TABLEACCESS_DENIED_ERROR
+show create view v1;
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # D.3) remove table-level SELECT privilege on t1
+--echo
+
+connection default;
+select user();
+
+--echo # Put back privilege removed in D.2
+grant show view on v1 to user1@localhost;
+--echo # And remove a next one:
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+--echo # Cannot see anything as it might expose some data from columns
+--echo # of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # Now remove each privilege to verify that it was needed for
+--echo # the trigger:
+--echo # D.4) remove table-level SELECT privilege on t2
+--echo
+
+connection default;
+select user();
+
+revoke select on t2 from user1@localhost;
+grant select (a) on t2 to user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+--echo # Cannot see anything as it might expose some data from
+--echo # columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # D.5) remove table-level SELECT privilege on t3
+--echo
+
+--echo
+connection default;
+select user();
+
+--echo # Put back privilege removed in D.4
+grant select on t2 to user1@localhost;
+--echo # And remove a next one:
+revoke select on t3 from user1@localhost;
+grant select (a) on t3 to user1@localhost;
+
+--echo
+connection con_user1;
+select user();
+
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+--echo # Cannot see substatement as it might expose some data from
+--echo # columns of t3
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+
+--echo
+--echo # Cleanup
+connection default;
+select user();
+drop user user1@localhost;
+disconnect con_user1;
+
+--echo
+--echo # ==========================================================
+--echo # Part E.
+--echo # Misc tests.
+--echo # ==========================================================
+--echo
+
+connection default;
+select user();
+drop view v1;
+create sql security definer view v1 as select * from t1 where 'secret';
+create user user1@localhost identified by '';
+grant create, insert, select on somedb.* to user1@localhost;
+grant create routine on somedb.* to user1@localhost;
+connect (con_user1, localhost, user1,, somedb);
+
+--echo
+connection con_user1;
+select user();
+
+--echo user1 cannot see view's body:
+--error 1142
+show create view v1;
+
+--echo user1 creates a procedure
+delimiter |;
+create procedure proc() sql security definer
+begin
+ set optimizer_trace="enabled=on";
+ set optimizer_trace_offset=0,optimizer_trace_limit=100;
+ select * from v1 limit 0;
+ create table leak select * from information_schema.optimizer_trace;
+ set optimizer_trace="enabled=off";
+end|
+delimiter ;|
+
+connection default;
+select user();
+
+--echo root runs procedure, without fear of risk as it is SQL SECURITY DEFINER
+call proc();
+
+--echo
+connection con_user1;
+select user();
+--echo user1 cannot see view's body:
+select * from leak;
+
+--echo
+--echo # Cleanup
+connection default;
+select user();
+drop database somedb;
+drop user user1@localhost;
+set @@global.optimizer_trace_max_mem_size = @old_size;
=== modified file 'mysql-test/r/optimizer_trace2_no_prot.result'
--- a/mysql-test/r/optimizer_trace2_no_prot.result 2011-04-13 15:36:01 +0000
+++ b/mysql-test/r/optimizer_trace2_no_prot.result 2011-05-04 20:53:28 +0000
@@ -17,7 +17,7 @@ f1("c")
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select f1("c") {
"steps": [
{
@@ -45,7 +45,15 @@ select f1("c") {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set dummy@2 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
select 1 into res from dual {
"steps": [
{
@@ -73,7 +81,7 @@ select 1 into res from dual {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select 2 into res from dual {
"steps": [
{
@@ -101,7 +109,11 @@ select 2 into res from dual {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 3 {
+ "steps": [
+ ] /* steps */
+} 0 0
set optimizer_trace_offset=default, optimizer_trace_limit=default;
drop function f1;
# check that if a tracing gets disabled in a routine's body,
@@ -123,7 +135,7 @@ f1("c")
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select f1("c") {
"steps": [
{
@@ -151,7 +163,15 @@ select f1("c") {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set dummy@2 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
set optimizer_trace_offset=default, optimizer_trace_limit=default;
select @@optimizer_trace;
@@optimizer_trace
@@ -1163,17 +1183,12 @@ SELECT POLYGON((SELECT 1 FROM (SELECT 1
ERROR 22007: Illegal non geometric '(select 1 from (select (1 = group_concat(`test`.`t1`.`f1` separator ',')) AS `1 IN (GROUP_CONCAT(t1.f1))` from `test`.`t1` join `test`.`t1` `t` group by `test`.`t`.`f1`) `d`)' value found during parsing
DROP TABLE t1;
-# Check that SQL PREPARE produces one statement, and
-# check that SQL EXECUTE produces two
+# Check that SQL PREPARE and SQL EXECUTE each produce one trace.
set optimizer_trace_offset=0, optimizer_trace_limit=100;
prepare stmt from "select 1";
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-prepare stmt from "select 1" {
- "steps": [
- ] /* steps */
-} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1 {
"steps": [
{
@@ -1187,17 +1202,13 @@ select 1 {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-execute stmt {
- "steps": [
- ] /* steps */
-} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1 {
"steps": [
{
@@ -1225,15 +1236,11 @@ select 1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
deallocate prepare stmt;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
-# Test of SELECTs in IF in stored routine. IF is not a real
-# command: not in enum_sql_command, does not have a dedicated
-# call to mysql_execute_command() for it; IF rather executes as
-# a part of the routine's call (CALL, for a procedure). It is
-# thus traced or not, as the routine's call.
+# Test of SELECTs in IF in stored routine.
# Same test for CASE WHEN.
create table t1 (a int);
@@ -1255,11 +1262,16 @@ else set @b=3;
end case;
end|
set optimizer_trace_offset=0, optimizer_trace_limit=100;
+set optimizer_trace_max_mem_size=20000;
call p1();
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
call p1() {
"steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 2(2) exists(select 1) {
+ "steps": [
{
"join_preparation": {
"select#": 2,
@@ -1290,7 +1302,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(1) {
+ "steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 4(4) exists(select 2) {
+ "steps": [
{
"join_preparation": {
"select#": 3,
@@ -1321,7 +1341,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(2) {
+ "steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 6(6) (select count(0) from `test`.`t1`) {
+ "steps": [
{
"join_preparation": {
"select#": 4,
@@ -1355,7 +1383,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(3) {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_case_expr (15) 0 (select count(`a`) from `test`.`t1` where (`a` > 1)) {
+ "steps": [
{
"join_preparation": {
"select#": 6,
@@ -1469,19 +1505,11 @@ call p1() {
} /* subselect_execution */
}
] /* steps */
-} 0
-insert into t1 values(1) {
+} 0 0
+jump_if_not 11(15) (case_expr@0 = 2) {
"steps": [
] /* steps */
-} 0
-insert into t1 values(2) {
- "steps": [
- ] /* steps */
-} 0
-insert into t1 values(3) {
- "steps": [
- ] /* steps */
-} 0
+} 0 0
select * from t1;
a
1
@@ -1490,6 +1518,299 @@ a
select @a,@b;
@a @b
3 2
+set optimizer_trace_max_mem_size=default;
+drop procedure p1;
+drop table t1;
+
+# Test that in a non-traced SQL command, substatements can be
+# traced
+
+create table t1(a int);
+insert into t1 values(1),(2);
+create function f1() returns int
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(b*10);
+return 36;
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+do f1();
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+set b@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+select 48 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 48 AS `48`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+select a into b from t1 limit 1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` limit 1"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.4034,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values( NAME_CONST('b',1)*10) {
+ "steps": [
+ ] /* steps */
+} 0 0
+freturn 3 36 {
+ "steps": [
+ ] /* steps */
+} 0 0
+drop function f1;
+drop table t1;
+
+# Test of tracing of subquery used in parameter of routine call
+
+create table t1(a int);
+insert into t1 values(1),(2);
+create procedure p1(x int)
+begin
+declare b int;
+set b=(select 2+x from dual);
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+call p1((select a from t1 limit 1));
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+call p1((select a from t1 limit 1)) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` limit 1"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "subselect_execution": {
+ "select#": 2,
+ "steps": [
+ {
+ "join_optimization": {
+ "select#": 2,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.4034,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 2,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+ } /* subselect_execution */
+ }
+ ] /* steps */
+} 0 0
+set b@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set b@1 (select (2 + x@0)) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 3,
+ "steps": [
+ {
+ "expanded_query": "/* select#3 */ select (2 + x@0)"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "subselect_execution": {
+ "select#": 3,
+ "steps": [
+ {
+ "join_optimization": {
+ "select#": 3,
+ "steps": [
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 3,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+ } /* subselect_execution */
+ }
+ ] /* steps */
+} 0 0
drop procedure p1;
drop table t1;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
@@ -1505,7 +1826,7 @@ concat(concat(_latin1'->',f1),_latin1'<-
-><-
-><-
select * from information_schema.optimizer_trace;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select concat(concat(_latin1'->',f1),_latin1'<-') from t1 {
"steps": [
{
@@ -1590,5 +1911,5 @@ select concat(concat(_latin1'->',f1),_la
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1;
=== modified file 'mysql-test/r/optimizer_trace2_ps_prot.result'
--- a/mysql-test/r/optimizer_trace2_ps_prot.result 2011-04-13 15:36:01 +0000
+++ b/mysql-test/r/optimizer_trace2_ps_prot.result 2011-05-04 20:53:28 +0000
@@ -17,7 +17,7 @@ f1("c")
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select f1("c") {
"steps": [
{
@@ -31,7 +31,7 @@ select f1("c") {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
select f1("c") {
"steps": [
{
@@ -59,7 +59,15 @@ select f1("c") {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set dummy@2 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
select 1 into res from dual {
"steps": [
{
@@ -87,7 +95,7 @@ select 1 into res from dual {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select 2 into res from dual {
"steps": [
{
@@ -115,7 +123,11 @@ select 2 into res from dual {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 3 {
+ "steps": [
+ ] /* steps */
+} 0 0
set optimizer_trace_offset=default, optimizer_trace_limit=default;
drop function f1;
# check that if a tracing gets disabled in a routine's body,
@@ -137,7 +149,7 @@ f1("c")
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select f1("c") {
"steps": [
{
@@ -151,7 +163,7 @@ select f1("c") {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
select f1("c") {
"steps": [
{
@@ -179,7 +191,15 @@ select f1("c") {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set dummy@2 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
set optimizer_trace_offset=default, optimizer_trace_limit=default;
select @@optimizer_trace;
@@optimizer_trace
@@ -1183,17 +1203,12 @@ SELECT POLYGON((SELECT 1 FROM (SELECT 1
ERROR 22007: Illegal non geometric '(select 1 from (select (1 = group_concat(`test`.`t1`.`f1` separator ',')) AS `1 IN (GROUP_CONCAT(t1.f1))` from `test`.`t1` join `test`.`t1` `t` group by `test`.`t`.`f1`) `d`)' value found during parsing
DROP TABLE t1;
-# Check that SQL PREPARE produces one statement, and
-# check that SQL EXECUTE produces two
+# Check that SQL PREPARE and SQL EXECUTE each produce one trace.
set optimizer_trace_offset=0, optimizer_trace_limit=100;
prepare stmt from "select 1";
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-prepare stmt from "select 1" {
- "steps": [
- ] /* steps */
-} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1 {
"steps": [
{
@@ -1207,17 +1222,13 @@ select 1 {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-execute stmt {
- "steps": [
- ] /* steps */
-} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1 {
"steps": [
{
@@ -1245,15 +1256,11 @@ select 1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
deallocate prepare stmt;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
-# Test of SELECTs in IF in stored routine. IF is not a real
-# command: not in enum_sql_command, does not have a dedicated
-# call to mysql_execute_command() for it; IF rather executes as
-# a part of the routine's call (CALL, for a procedure). It is
-# thus traced or not, as the routine's call.
+# Test of SELECTs in IF in stored routine.
# Same test for CASE WHEN.
create table t1 (a int);
@@ -1275,11 +1282,16 @@ else set @b=3;
end case;
end|
set optimizer_trace_offset=0, optimizer_trace_limit=100;
+set optimizer_trace_max_mem_size=20000;
call p1();
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
call p1() {
"steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 2(2) exists(select 1) {
+ "steps": [
{
"join_preparation": {
"select#": 2,
@@ -1310,7 +1322,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(1) {
+ "steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 4(4) exists(select 2) {
+ "steps": [
{
"join_preparation": {
"select#": 3,
@@ -1341,7 +1361,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(2) {
+ "steps": [
+ ] /* steps */
+} 0 0
+jump_if_not 6(6) (select count(0) from `test`.`t1`) {
+ "steps": [
{
"join_preparation": {
"select#": 4,
@@ -1375,7 +1403,15 @@ call p1() {
}
] /* steps */
} /* subselect_execution */
- },
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values(3) {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_case_expr (15) 0 (select count(`a`) from `test`.`t1` where (`a` > 1)) {
+ "steps": [
{
"join_preparation": {
"select#": 6,
@@ -1489,19 +1525,11 @@ call p1() {
} /* subselect_execution */
}
] /* steps */
-} 0
-insert into t1 values(1) {
+} 0 0
+jump_if_not 11(15) (case_expr@0 = 2) {
"steps": [
] /* steps */
-} 0
-insert into t1 values(2) {
- "steps": [
- ] /* steps */
-} 0
-insert into t1 values(3) {
- "steps": [
- ] /* steps */
-} 0
+} 0 0
select * from t1;
a
1
@@ -1510,6 +1538,299 @@ a
select @a,@b;
@a @b
3 2
+set optimizer_trace_max_mem_size=default;
+drop procedure p1;
+drop table t1;
+
+# Test that in a non-traced SQL command, substatements can be
+# traced
+
+create table t1(a int);
+insert into t1 values(1),(2);
+create function f1() returns int
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(b*10);
+return 36;
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+do f1();
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+set b@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+select 48 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 48 AS `48`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+select a into b from t1 limit 1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` limit 1"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.4034,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+insert into t1 values( NAME_CONST('b',1)*10) {
+ "steps": [
+ ] /* steps */
+} 0 0
+freturn 3 36 {
+ "steps": [
+ ] /* steps */
+} 0 0
+drop function f1;
+drop table t1;
+
+# Test of tracing of subquery used in parameter of routine call
+
+create table t1(a int);
+insert into t1 values(1),(2);
+create procedure p1(x int)
+begin
+declare b int;
+set b=(select 2+x from dual);
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+call p1((select a from t1 limit 1));
+select * from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+call p1((select a from t1 limit 1)) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `test`.`t1`.`a` from `test`.`t1` limit 1"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "subselect_execution": {
+ "select#": 2,
+ "steps": [
+ {
+ "join_optimization": {
+ "select#": 2,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.4034,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 2,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+ } /* subselect_execution */
+ }
+ ] /* steps */
+} 0 0
+set b@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+set b@1 (select (2 + x@0)) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 3,
+ "steps": [
+ {
+ "expanded_query": "/* select#3 */ select (2 + x@0)"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "subselect_execution": {
+ "select#": 3,
+ "steps": [
+ {
+ "join_optimization": {
+ "select#": 3,
+ "steps": [
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 3,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+ } /* subselect_execution */
+ }
+ ] /* steps */
+} 0 0
drop procedure p1;
drop table t1;
set optimizer_trace_offset=default, optimizer_trace_limit=default;
@@ -1525,7 +1846,7 @@ concat(concat(_latin1'->',f1),_latin1'<-
-><-
-><-
select * from information_schema.optimizer_trace;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select concat(concat(_latin1'->',f1),_latin1'<-') from t1 {
"steps": [
{
@@ -1610,5 +1931,5 @@ select concat(concat(_latin1'->',f1),_la
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1;
=== removed file 'mysql-test/r/optimizer_trace_bugs.result'
--- a/mysql-test/r/optimizer_trace_bugs.result 2010-08-09 15:09:55 +0000
+++ b/mysql-test/r/optimizer_trace_bugs.result 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-select 1;
-1
-1
=== modified file 'mysql-test/r/optimizer_trace_debug.result'
--- a/mysql-test/r/optimizer_trace_debug.result 2011-03-08 07:18:14 +0000
+++ b/mysql-test/r/optimizer_trace_debug.result 2011-05-04 20:53:28 +0000
@@ -1,27 +1,21 @@
# We want to make sure that the common case of
-# a connection which has not enabled tracing, or is
-# running SQL commands which are excluded from
-# tracing, or commands which use I_S.OPTIMIZER_TRACE,
-# outside of any tricky stored-routine scenarios tested
-# in optimizer_trace2.test, are optimized, i.e. no trace is
-# created, even a dummy internal one invisible in I_S.
-set debug="d,opt_trace_should_not_start";
+# a connection which has not enabled tracing,
+# is optimized, i.e. neither Opt_trace_context_impl nor
+# Opt_trace_context_stmt is created.
+set debug="d,no_new_opt_trace_stmt";
select 1;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
set @a=25;
-set optimizer_trace="enabled=on";
-select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
set debug="default";
+set optimizer_trace="enabled=on";
select 2;
2
2
-set debug="d,opt_trace_should_not_start";
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 2 {
"steps": [
{
@@ -49,14 +43,14 @@ select 2 {
}
}
]
-} 0
-set @a=25;
+} 0 0
set optimizer_trace="enabled=off";
+set debug="d,no_new_opt_trace_stmt";
select 3;
3
3
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 2 {
"steps": [
{
@@ -84,5 +78,4 @@ select 2 {
}
}
]
-} 0
-set optimizer_trace=default;
+} 0 0
=== modified file 'mysql-test/r/optimizer_trace_no_prot.result'
--- a/mysql-test/r/optimizer_trace_no_prot.result 2011-03-21 17:55:41 +0000
+++ b/mysql-test/r/optimizer_trace_no_prot.result 2011-05-04 20:53:28 +0000
@@ -1,9 +1,9 @@
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
set optimizer_trace_max_mem_size=1048576;
set @@session.optimizer_trace="enabled=on";
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
CREATE TABLE t5 (c int);
INSERT INTO t5 VALUES (NULL);
CREATE TABLE t6 (d int , KEY (d));
@@ -12,7 +12,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {
"steps": [
{
@@ -167,7 +167,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
}
}
]
-} 0
+} 0 0
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
@@ -177,8 +177,8 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {"steps": [{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": [{"expanded_query": "/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)"}]}},{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)) AS `RESULT` from `test`.`t5`"}]}},{"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_computation": [],"attached_conditions_summary": []}},{"refine_plan": []}]}},{"join_execution": {"select#": 1,"steps": [{"subselect_execution": {"select#": 2,"steps": [{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","steps": [{"transformation": "equality_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "constant_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "trivial_condition_removal","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"}]}},{"ref_optimizer_key_uses": [{"database": "test","table": "t6","field": "d","equals": "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},"setup_range_conditions": [{"impossible_condition": {"cause": "comparison_with_null_always_false"}}],"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}},{"join_execution": {"select#": 2,"steps": []}}]}}]}}]} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {"steps": [{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": [{"expanded_query": "/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)"}]}},{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)) AS `RESULT` from `test`.`t5`"}]}},{"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_computation": [],"attached_conditions_summary": []}},{"refine_plan": []}]}},{"join_execution": {"select#": 1,"steps": [{"subselect_execution": {"select#": 2,"steps": [{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","steps": [{"transformation": "equality_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "constant_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "trivial_condition_removal","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"}]}},{"ref_optimizer_key_uses": [{"database": "test","table": "t6","field": "d","equals": "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},"setup_range_conditions": [{"impossible_condition": {"cause": "comparison_with_null_always_false"}}],"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}},{"join_execution": {"select#": 2,"steps": []}}]}}]}}]} 0 0
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
@@ -189,7 +189,7 @@ id select_type table type possible_keys
1 PRIMARY t5 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -337,12 +337,12 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
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
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -497,7 +497,7 @@ SELECT /* should be last */ (SELECT 1 FR
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@session.optimizer_trace="enabled=off";
SELECT /* bug if you see this*/ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
RESULT
@@ -510,7 +510,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -842,11 +842,11 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
} /* join_execution */
}
] /* steps */
-} 0
+} 0 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 * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
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)) {
"steps": [
{
@@ -1164,7 +1164,7 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
(@query:=QUERY)+NULL (@trace:=TRACE)+NULL
NULL NULL
@@ -1201,22 +1201,22 @@ select 1;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select 1 521
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+select 1 521 0
set optimizer_trace_max_mem_size=0;
select 1;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
- 529
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ 529 0
set optimizer_trace_max_mem_size=1048576;
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t5 system NULL NULL NULL NULL 1
1 PRIMARY t6 ref d d 5 const 1 Using where; Using index; FirstMatch(t5)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null) {
"steps": [
{
@@ -1499,14 +1499,14 @@ explain SELECT c FROM t5 where c+1 in (s
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off";
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t5 system NULL NULL NULL NULL 1
2 SUBQUERY t6 ref d d 5 const 1 Using where; Using index
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null) {
"steps": [
{
@@ -1772,7 +1772,7 @@ explain SELECT c FROM t5 where c+1 in (s
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
CREATE TABLE t1 (s1 CHAR(5),
s2 CHAR(5));
@@ -1784,7 +1784,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <nop>((`test`.`t1`.`s1` > (/* select#2 */ select min(`test`.`t1`.`s2`) from `test`.`t1`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 > any (select s2 from t1) {
"steps": [
{
@@ -1988,7 +1988,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
explain extended select * from t1 where s1 > any (select max(s2) from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where
@@ -1996,7 +1996,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <nop>((`test`.`t1`.`s1` > <min>(/* select#2 */ select max(`test`.`t1`.`s2`) from `test`.`t1`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 > any (select max(s2) from t1) {
"steps": [
{
@@ -2200,7 +2200,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off,materialization=off";
explain extended select * from t1 where s1 in (select s2 from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
@@ -2209,7 +2209,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`s1`,<exists>(/* select#2 */ select 1 from `test`.`t1` where (<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 in (select s2 from t1) {
"steps": [
{
@@ -2453,7 +2453,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
explain extended select * from t1 where (s1,s2) in (select s2,s1 from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where
@@ -2461,7 +2461,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`s1`,`test`.`t1`.`s2`),<exists>(/* select#2 */ select `test`.`t1`.`s2`,`test`.`t1`.`s1` from `test`.`t1` where ((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where (s1,s2) in (select s2,s1 from t1) {
"steps": [
{
@@ -2705,7 +2705,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
drop table t1;
create table t1(a int);
@@ -2718,7 +2718,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using join buffer (BNL, incremental buffers)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1,t2 {
"steps": [
{
@@ -2877,7 +2877,7 @@ explain select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select @@optimizer_trace_features;
@@optimizer_trace_features
greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on
@@ -2887,7 +2887,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using join buffer (BNL, incremental buffers)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1,t2 {
"steps": [
{
@@ -2971,7 +2971,7 @@ explain select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features=default;
set @@session.optimizer_prune_level=default;
drop table t1, t2;
@@ -3011,7 +3011,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,<exists>(/* select#2 */ select 1 from `test`.`t2_16` where ((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select left(a1,7), left(a2,7)
from t1_16
where a1 in (select b1 from t2_16 where b1 > '0') {
@@ -3258,7 +3258,7 @@ where a1 in (select b1 from t2_16 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1_16,t2_16,t3_16;
set @@optimizer_switch=default;
CREATE table t1 ( c1 integer );
@@ -3274,7 +3274,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
c1 c2
1 1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2
WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) ) {
"steps": [
@@ -3610,12 +3610,12 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SELECT * FROM t1 WHERE c1=5 UNION SELECT * FROM t2 WHERE c2=5;
c1
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * FROM t1 WHERE c1=5 UNION SELECT * FROM t2 WHERE c2=5 {
"steps": [
{
@@ -3910,7 +3910,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off";
explain
select * from t1
@@ -3924,7 +3924,7 @@ id select_type table type possible_keys
3 SUBQUERY t2 ALL NULL NULL NULL NULL 3
2 SUBQUERY t2 ALL NULL NULL NULL NULL 3
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain
select * from t1
where concat(c1,'x') IN
@@ -4255,7 +4255,7 @@ concat(c1,'y') IN
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
DROP TABLE t1,t2;
create table t1 (a int);
@@ -4266,7 +4266,7 @@ select * from t1,t2;
a a
1 1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1,t2 {
"steps": [
{
@@ -4325,7 +4325,7 @@ select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
create table t3 (a int, b int);
create table t4 (a int primary key);
insert into t4 values(1),(2);
@@ -4675,7 +4675,7 @@ a a
1 NULL
1 NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1 left join t2 on t2.a=500 where t2.a is NULL {
"steps": [
{
@@ -4820,7 +4820,7 @@ select * from t1 left join t2 on t2.a=50
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1,t2;
create table t1(a int, b int);
insert into t1 values(1,NULL),(NULL,2);
@@ -4829,7 +4829,7 @@ insert into t2 values(1,1),(2,2);
select * from t1 where (t1.a,t1.b) not in (select c,d from t2 where c>0);
a b
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1 where (t1.a,t1.b) not in (select c,d from t2 where c>0) {
"steps": [
{
@@ -5110,7 +5110,7 @@ select * from t1 where (t1.a,t1.b) not i
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select t1.a,avg(t2.c) as moyenne from t1, t2 where t2.c>-1
group by t1.a having moyenne<>0;
a moyenne
@@ -5374,7 +5374,7 @@ trace
drop table t1,t2;
update t6 set d=5 where d is NULL;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
update t6 set d=5 where d is NULL {
"steps": [
{
@@ -5435,10 +5435,10 @@ update t6 set d=5 where d is NULL {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
delete from t6 where d=5;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete from t6 where d=5 {
"steps": [
{
@@ -5495,17 +5495,17 @@ delete from t6 where d=5 {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
insert into t6 values(6),(7),(8);
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into t6 values(6),(7),(8) {
"steps": [
] /* steps */
-} 0
+} 0 0
insert into t6 select * from t6 where d>7;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into t6 select * from t6 where d>7 {
"steps": [
{
@@ -5656,10 +5656,10 @@ insert into t6 select * from t6 where d>
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-4 where d>7000;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-4 where d>7000 {
"steps": [
{
@@ -5823,10 +5823,10 @@ update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
delete t6 from t5, t6 where d>7000;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete t6 from t5, t6 where d>7000 {
"steps": [
{
@@ -5984,10 +5984,10 @@ delete t6 from t5, t6 where d>7000 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=2,optimizer_trace_limit=2;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1;
1
1
@@ -6004,7 +6004,7 @@ select 5;
5
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 3 {
"steps": [
{
@@ -6032,7 +6032,7 @@ select 3 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select 4 {
"steps": [
{
@@ -6060,10 +6060,10 @@ select 4 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=-2,optimizer_trace_limit=2;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1;
1
1
@@ -6080,7 +6080,7 @@ select 5;
5
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 4 {
"steps": [
{
@@ -6108,7 +6108,7 @@ select 4 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select 5 {
"steps": [
{
@@ -6136,10 +6136,10 @@ select 5 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=default,optimizer_trace_limit=default;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
create table t1 (
id char(16) not null default '',
data int not null
@@ -6163,281 +6163,35 @@ select f1()|
f1()
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
+} 0 0
select s, f1() from t2 order by s desc|
s f1()
c 3
b 3
a 3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
+} 0 0
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
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
-set optimizer_trace_offset=-7, optimizer_trace_limit=7|
-select @@optimizer_trace_offset, @@optimizer_trace_limit|
-@@optimizer_trace_offset @@optimizer_trace_limit
--7 7
+} 0 0
+set optimizer_trace_offset=-20, optimizer_trace_limit=20|
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
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t6 where d in (select f1() from t2 where s="c") {
"steps": [
{
@@ -6798,7 +6552,1240 @@ select * from t6 where d in (select f1()
},
{
"database": "test",
- "table": "t2",
+ "table": "t2",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+select count(*) from information_schema.OPTIMIZER_TRACE|
+count(*)
+11
+set optimizer_trace_offset=3, optimizer_trace_limit=1|
+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 INSUFFICIENT_PRIVILEGES
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
+ }
+ ] /* steps */
+} 0 0
+create procedure p1(arg char(1))
+begin
+declare res int;
+select d into res from t6 where d in (select f1() from t2 where s=arg);
+select d+1 into res from t6 where d=res+1;
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+call p1("c")|
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+select * from information_schema.OPTIMIZER_TRACE|
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+call p1("c") {
+ "steps": [
+ ] /* steps */
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = arg@0)"
+ },
+ {
+ "transformation": {
+ "select#": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ } /* transformation */
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d` from `test`.`t6` where `test`.`t6`.`d` in (/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = arg@0))"
+ }
+ ] /* 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` = arg@0) and (`test`.`t6`.`d` = `f1`()))",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "(1 and multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "(1 and multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "(multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "database": "test",
+ "table": "t6",
+ "field": "d",
+ "equals": "`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 */,
+ "setup_range_conditions": [
+ ] /* setup_range_conditions */,
+ "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.6212,
+ "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.6212,
+ "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": 5.8289,
+ "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.2,
+ "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.8213,
+ "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.2213,
+ "records": 1,
+ "chosen": true
+ },
+ {
+ "strategy": "MaterializationLookup",
+ "cost": 4.0212,
+ "records": 1,
+ "duplicate_tables_left": false,
+ "chosen": false
+ },
+ {
+ "strategy": "DuplicatesWeedout",
+ "cost": 3.8213,
+ "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` = arg@0))",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t6",
+ "attached": null
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t6"
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "database": "test",
+ "table": "t6",
+ "field": "d",
+ "equals": "(res@1 + 1)",
+ "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 */,
+ "setup_range_conditions": [
+ {
+ "impossible_condition": {
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */
+ }
+ ] /* setup_range_conditions */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
+ }
+ ] /* records_estimation */
+ }
+ ] /* steps */,
+ "empty_result": {
+ "cause": "no matching row in const table"
+ } /* empty_result */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+create trigger trg1 before insert on t2 for each row
+begin
+set new.s=f1();
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100|
+insert into t2 select d,100,200 from t6 where d is not null|
+select * from information_schema.OPTIMIZER_TRACE|
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+insert into t2 select d,100,200 from t6 where d is not null {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d`,100 AS `100`,200 AS `200` from `test`.`t6` where (`test`.`t6`.`d` is not null)"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t6`.`d` is not null)",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ ] /* 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 */,
+ "setup_range_conditions": [
+ ] /* setup_range_conditions */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "NULL < d"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 4,
+ "cost": 1.8798,
+ "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": "t6",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.8068,
+ "records_for_plan": 4,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t6`.`d` is not null)",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t6",
+ "attached": "(`test`.`t6`.`d` is not null)"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t6",
+ "scan_type": "index"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
"scan_type": "table"
}
] /* refine_plan */
@@ -6814,11 +7801,23 @@ select * from t6 where d in (select f1()
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -6832,7 +7831,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -6917,11 +7916,23 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -6935,7 +7946,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7020,12 +8031,23 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
-set optimizer_trace_offset=2, optimizer_trace_limit=1|
-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
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -7039,126 +8061,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
-set optimizer_trace_offset=default, optimizer_trace_limit=default|
-create procedure p1(arg char(1))
-begin
-declare res int;
-select d into res from t6 where d in (select f1() from t2 where s=arg);
-select d+1 into res from t6 where d=res+1;
-end|
-call p1("c")|
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
-select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 {
- "steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "condition_processing": {
- "condition": "WHERE",
- "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
- "steps": [
- {
- "transformation": "equality_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- },
- {
- "transformation": "constant_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- },
- {
- "transformation": "trivial_condition_removal",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- }
- ] /* steps */
- } /* condition_processing */
- },
- {
- "ref_optimizer_key_uses": [
- {
- "database": "test",
- "table": "t6",
- "field": "d",
- "equals": "(res@1 + 1)",
- "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 */,
- "setup_range_conditions": [
- {
- "impossible_condition": {
- "cause": "comparison_with_null_always_false"
- } /* impossible_condition */
- }
- ] /* setup_range_conditions */,
- "impossible_range": true
- } /* range_analysis */,
- "records": 0,
- "cause": "impossible_where_condition"
- }
- ] /* records_estimation */
- }
- ] /* steps */,
- "empty_result": {
- "cause": "no matching row in const table"
- } /* empty_result */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
- ] /* steps */
-} 0
-create trigger trg1 before insert on t2 for each row
-begin
-set new.s=f1();
-end|
-insert into t2 select d,100,200 from t6 where d is not null|
-select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7243,7 +8146,11 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
select * from t2|
s i d
a 1 1
@@ -7253,14 +8160,15 @@ c 3 3
3 100 200
3 100 200
3 100 200
-prepare stmt from 'call p1(?)';
-select QUERY from information_schema.OPTIMIZER_TRACE;
-QUERY
-call p1(?)
+prepare stmt from 'select count(*) from t1 where t1.data=?';
set @param="c";
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
+count(*)
+0
+select count(*) from information_schema.OPTIMIZER_TRACE;
+count(*)
+1
select TRACE into @trace from information_schema.OPTIMIZER_TRACE;
select @trace;
@trace
@@ -7271,7 +8179,7 @@ select @trace;
"select#": 1,
"steps": [
{
- "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
+ "expanded_query": "/* select#1 */ select count(0) AS `count(*)` from `test`.`t1` where (`test`.`t1`.`data` = 'c')"
}
] /* steps */
} /* join_preparation */
@@ -7283,76 +8191,85 @@ select @trace;
{
"condition_processing": {
"condition": "WHERE",
- "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
+ "original_condition": "(`test`.`t1`.`data` = 'c')",
"steps": [
{
"transformation": "equality_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
},
{
"transformation": "constant_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
},
{
"transformation": "trivial_condition_removal",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
}
] /* steps */
} /* condition_processing */
},
{
"ref_optimizer_key_uses": [
+ ] /* ref_optimizer_key_uses */
+ },
+ {
+ "records_estimation": [
{
"database": "test",
- "table": "t6",
- "field": "d",
- "equals": "(res@1 + 1)",
- "null_rejecting": false
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
}
- ] /* ref_optimizer_key_uses */
+ ] /* records_estimation */
},
{
- "records_estimation": [
+ "considered_execution_plans": [
{
"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 */,
- "setup_range_conditions": [
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
{
- "impossible_condition": {
- "cause": "comparison_with_null_always_false"
- } /* impossible_condition */
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 2,
+ "cost": 2.0154,
+ "chosen": true
}
- ] /* setup_range_conditions */,
- "impossible_range": true
- } /* range_analysis */,
- "records": 0,
- "cause": "impossible_where_condition"
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
}
- ] /* records_estimation */
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t1`.`data` = 'c')",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "(`test`.`t1`.`data` = 'c')"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
}
- ] /* steps */,
- "empty_result": {
- "cause": "no matching row in const table"
- } /* empty_result */
+ ] /* steps */
} /* join_optimization */
},
{
@@ -7364,15 +8281,19 @@ select @trace;
}
] /* steps */
}
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
+count(*)
+0
+select count(*) from information_schema.OPTIMIZER_TRACE;
+count(*)
+1
select TRACE into @trace2 from information_schema.OPTIMIZER_TRACE;
select @trace=@trace2;
@trace=@trace2
1
drop procedure p1;
-create table optt like information_schema.OPTIMIZER_TRACE;
+create temporary table optt like information_schema.OPTIMIZER_TRACE;
create procedure p1(arg char(1))
begin
declare res int;
@@ -7390,7 +8311,7 @@ call p1("c")|
Warnings:
Warning 1329 No data - zero rows fetched, selected, or processed
select * from optt|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) {
"steps": [
{
@@ -7732,11 +8653,15 @@ select d into res from t6 where d in (se
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -7750,7 +8675,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7835,11 +8760,19 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -7853,7 +8786,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7938,12 +8871,16 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
select @@optimizer_trace|
@@optimizer_trace
enabled=off,end_marker=on,one_line=off
set optimizer_trace="enabled=on";
-drop table optt;
+drop temporary table optt;
drop function f1;
drop procedure p1;
drop trigger trg1;
@@ -7952,7 +8889,7 @@ explain select * from v1 where id="b";
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from v1 where id="b" {
"steps": [
{
@@ -8070,10 +9007,10 @@ explain select * from v1 where id="b" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
insert into v1 values("z", 100);
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into v1 values("z", 100) {
"steps": [
{
@@ -8086,10 +9023,10 @@ insert into v1 values("z", 100) {
} /* view */
}
] /* steps */
-} 0
+} 0 0
delete from v1 where data=100;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete from v1 where data=100 {
"steps": [
{
@@ -8112,7 +9049,7 @@ delete from v1 where data=100 {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
drop view v1;
create view v1 as select * from t1 where id < "c" limit 2;
explain select * from v1 where id="b";
@@ -8120,7 +9057,7 @@ id select_type table type possible_keys
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 Using where
2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using where
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from v1 where id="b" {
"steps": [
{
@@ -8350,14 +9287,14 @@ explain select * from v1 where id="b" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop view v1;
select * from information_schema.session_variables where
VARIABLE_NAME="optimizer_trace";
VARIABLE_NAME VARIABLE_VALUE
OPTIMIZER_TRACE enabled=on,end_marker=on,one_line=off
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from information_schema.session_variables where
VARIABLE_NAME="optimizer_trace" {
"steps": [
@@ -8467,7 +9404,7 @@ VARIABLE_NAME="optimizer_trace" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace="end_marker=off";
select 1 union select 2;
1
@@ -8612,7 +9549,7 @@ 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,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select "abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col {
"steps": [
{
@@ -8640,7 +9577,7 @@ select "abc11111111111111111111111111111
}
}
]
-} 0
+} 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 2011-03-21 17:55:41 +0000
+++ b/mysql-test/r/optimizer_trace_ps_prot.result 2011-05-04 20:53:28 +0000
@@ -1,9 +1,9 @@
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
set optimizer_trace_max_mem_size=1048576;
set @@session.optimizer_trace="enabled=on";
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
CREATE TABLE t5 (c int);
INSERT INTO t5 VALUES (NULL);
CREATE TABLE t6 (d int , KEY (d));
@@ -12,7 +12,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {
"steps": [
{
@@ -167,7 +167,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
}
}
]
-} 0
+} 0 0
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
@@ -177,8 +177,8 @@ SELECT (SELECT 1 FROM t6 WHERE d = c) AS
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {"steps": [{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": [{"expanded_query": "/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)"}]}},{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)) AS `RESULT` from `test`.`t5`"}]}},{"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_computation": [],"attached_conditions_summary": []}},{"refine_plan": []}]}},{"join_execution": {"select#": 1,"steps": [{"subselect_execution": {"select#": 2,"steps": [{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","steps": [{"transformation": "equality_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "constant_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "trivial_condition_removal","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"}]}},{"ref_optimizer_key_uses": [{"database": "test","table": "t6","field": "d","equals": "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},"setup_range_conditions": [{"impossible_condition": {"cause": "comparison_with_null_always_false"}}],"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}},{"join_execution": {"select#": 2,"steps": []}}]}}]}}]} 0
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+SELECT (SELECT 1 FROM t6 WHERE d = c) AS RESULT FROM t5 {"steps": [{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": [{"expanded_query": "/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)"}]}},{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`t6` where (`test`.`t6`.`d` = `test`.`t5`.`c`)) AS `RESULT` from `test`.`t5`"}]}},{"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_computation": [],"attached_conditions_summary": []}},{"refine_plan": []}]}},{"join_execution": {"select#": 1,"steps": [{"subselect_execution": {"select#": 2,"steps": [{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`t6`.`d` = NULL)","steps": [{"transformation": "equality_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "constant_propagation","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"},{"transformation": "trivial_condition_removal","resulting_condition": "multiple equal(NULL, `test`.`t6`.`d`)"}]}},{"ref_optimizer_key_uses": [{"database": "test","table": "t6","field": "d","equals": "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},"setup_range_conditions": [{"impossible_condition": {"cause": "comparison_with_null_always_false"}}],"impossible_range": true},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}},{"join_execution": {"select#": 2,"steps": []}}]}}]}}]} 0 0
select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
from information_schema.OPTIMIZER_TRACE;
(1-length(replace(TRACE, " ", ""))/length(TRACE))*100
@@ -189,7 +189,7 @@ id select_type table type possible_keys
1 PRIMARY t5 system NULL NULL NULL NULL 1
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -337,12 +337,12 @@ EXPLAIN SELECT (SELECT 1 FROM t6 WHERE d
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
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
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT /* should be last */ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -497,7 +497,7 @@ SELECT /* should be last */ (SELECT 1 FR
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@session.optimizer_trace="enabled=off";
SELECT /* bug if you see this*/ (SELECT 1 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 ;
RESULT
@@ -510,7 +510,7 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
RESULT
NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT 1 FROM t6 WHERE d = ifnull(c,null) UNION SELECT 2 FROM t6 WHERE d = ifnull(c,null)) AS RESULT FROM t5 {
"steps": [
{
@@ -842,11 +842,11 @@ SELECT (SELECT 1 FROM t6 WHERE d = ifnul
} /* join_execution */
}
] /* steps */
-} 0
+} 0 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 * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
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)) {
"steps": [
{
@@ -1148,7 +1148,7 @@ SELECT * FROM t5 WHERE 5 IN (SELECT 1 FR
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select (@query:=QUERY)+NULL, (@trace:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
(@query:=QUERY)+NULL (@trace:=TRACE)+NULL
NULL NULL
@@ -1185,22 +1185,22 @@ select 1;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select 1 521
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+select 1 521 0
set optimizer_trace_max_mem_size=0;
select 1;
1
1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
- 529
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+ 529 0
set optimizer_trace_max_mem_size=1048576;
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t5 system NULL NULL NULL NULL 1
1 PRIMARY t6 ref d d 5 const 1 Using where; Using index; FirstMatch(t5)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null) {
"steps": [
{
@@ -1483,14 +1483,14 @@ explain SELECT c FROM t5 where c+1 in (s
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off";
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t5 system NULL NULL NULL NULL 1
2 SUBQUERY t6 ref d d 5 const 1 Using where; Using index
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain SELECT c FROM t5 where c+1 in (select d+1 from t6 where d is null) {
"steps": [
{
@@ -1756,7 +1756,7 @@ explain SELECT c FROM t5 where c+1 in (s
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
CREATE TABLE t1 (s1 CHAR(5),
s2 CHAR(5));
@@ -1768,7 +1768,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <nop>((`test`.`t1`.`s1` > (/* select#2 */ select min(`test`.`t1`.`s2`) from `test`.`t1`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 > any (select s2 from t1) {
"steps": [
{
@@ -1972,7 +1972,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
explain extended select * from t1 where s1 > any (select max(s2) from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where
@@ -1980,7 +1980,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <nop>((`test`.`t1`.`s1` > <min>(/* select#2 */ select max(`test`.`t1`.`s2`) from `test`.`t1`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 > any (select max(s2) from t1) {
"steps": [
{
@@ -2184,7 +2184,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off,materialization=off";
explain extended select * from t1 where s1 in (select s2 from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
@@ -2193,7 +2193,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <in_optimizer>(`test`.`t1`.`s1`,<exists>(/* select#2 */ select 1 from `test`.`t1` where (<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`)))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where s1 in (select s2 from t1) {
"steps": [
{
@@ -2437,7 +2437,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
explain extended select * from t1 where (s1,s2) in (select s2,s1 from t1);
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where
@@ -2445,7 +2445,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select `test`.`t1`.`s1` AS `s1`,`test`.`t1`.`s2` AS `s2` from `test`.`t1` where <in_optimizer>((`test`.`t1`.`s1`,`test`.`t1`.`s2`),<exists>(/* select#2 */ select `test`.`t1`.`s2`,`test`.`t1`.`s1` from `test`.`t1` where ((<cache>(`test`.`t1`.`s1`) = `test`.`t1`.`s2`) and (<cache>(`test`.`t1`.`s2`) = `test`.`t1`.`s1`))))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select * from t1 where (s1,s2) in (select s2,s1 from t1) {
"steps": [
{
@@ -2689,7 +2689,7 @@ explain extended select * from t1 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
drop table t1;
create table t1(a int);
@@ -2702,7 +2702,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using join buffer (BNL, incremental buffers)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1,t2 {
"steps": [
{
@@ -2861,7 +2861,7 @@ explain select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select @@optimizer_trace_features;
@@optimizer_trace_features
greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on
@@ -2871,7 +2871,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using join buffer (BNL, incremental buffers)
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from t1,t2 {
"steps": [
{
@@ -2955,7 +2955,7 @@ explain select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features=default;
set @@session.optimizer_prune_level=default;
drop table t1, t2;
@@ -2995,7 +2995,7 @@ id select_type table type possible_keys
Warnings:
Note 1003 /* select#1 */ select left(`test`.`t1_16`.`a1`,7) AS `left(a1,7)`,left(`test`.`t1_16`.`a2`,7) AS `left(a2,7)` from `test`.`t1_16` where <in_optimizer>(`test`.`t1_16`.`a1`,<exists>(/* select#2 */ select 1 from `test`.`t2_16` where ((`test`.`t2_16`.`b1` > '0') and (<cache>(`test`.`t1_16`.`a1`) = `test`.`t2_16`.`b1`))))
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain extended select left(a1,7), left(a2,7)
from t1_16
where a1 in (select b1 from t2_16 where b1 > '0') {
@@ -3242,7 +3242,7 @@ where a1 in (select b1 from t2_16 where
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1_16,t2_16,t3_16;
set @@optimizer_switch=default;
CREATE table t1 ( c1 integer );
@@ -3258,7 +3258,7 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
c1 c2
1 1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * FROM t1 LEFT JOIN t2 ON c1 = c2
WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2 IN ( 1 ) ) {
"steps": [
@@ -3594,12 +3594,12 @@ WHERE c2 IN ( SELECT c2 FROM t2 WHERE c2
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SELECT * FROM t1 WHERE c1=5 UNION SELECT * FROM t2 WHERE c2=5;
c1
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * FROM t1 WHERE c1=5 UNION SELECT * FROM t2 WHERE c2=5 {
"steps": [
{
@@ -3894,7 +3894,7 @@ SELECT * FROM t1 WHERE c1=5 UNION SELECT
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch="semijoin=off";
explain
select * from t1
@@ -3908,7 +3908,7 @@ id select_type table type possible_keys
3 SUBQUERY t2 ALL NULL NULL NULL NULL 3
2 SUBQUERY t2 ALL NULL NULL NULL NULL 3
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain
select * from t1
where concat(c1,'x') IN
@@ -4239,7 +4239,7 @@ concat(c1,'y') IN
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_switch=default;
DROP TABLE t1,t2;
create table t1 (a int);
@@ -4250,7 +4250,7 @@ select * from t1,t2;
a a
1 1
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1,t2 {
"steps": [
{
@@ -4309,7 +4309,7 @@ select * from t1,t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
create table t3 (a int, b int);
create table t4 (a int primary key);
insert into t4 values(1),(2);
@@ -4659,7 +4659,7 @@ a a
1 NULL
1 NULL
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1 left join t2 on t2.a=500 where t2.a is NULL {
"steps": [
{
@@ -4804,7 +4804,7 @@ select * from t1 left join t2 on t2.a=50
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1,t2;
create table t1(a int, b int);
insert into t1 values(1,NULL),(NULL,2);
@@ -4813,7 +4813,7 @@ insert into t2 values(1,1),(2,2);
select * from t1 where (t1.a,t1.b) not in (select c,d from t2 where c>0);
a b
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t1 where (t1.a,t1.b) not in (select c,d from t2 where c>0) {
"steps": [
{
@@ -5086,7 +5086,7 @@ select * from t1 where (t1.a,t1.b) not i
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
select t1.a,avg(t2.c) as moyenne from t1, t2 where t2.c>-1
group by t1.a having moyenne<>0;
a moyenne
@@ -5350,7 +5350,7 @@ trace
drop table t1,t2;
update t6 set d=5 where d is NULL;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
update t6 set d=5 where d is NULL {
"steps": [
{
@@ -5411,10 +5411,10 @@ update t6 set d=5 where d is NULL {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
delete from t6 where d=5;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete from t6 where d=5 {
"steps": [
{
@@ -5471,17 +5471,17 @@ delete from t6 where d=5 {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
insert into t6 values(6),(7),(8);
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into t6 values(6),(7),(8) {
"steps": [
] /* steps */
-} 0
+} 0 0
insert into t6 select * from t6 where d>7;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into t6 select * from t6 where d>7 {
"steps": [
{
@@ -5632,10 +5632,10 @@ insert into t6 select * from t6 where d>
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-4 where d>7000;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-4 where d>7000 {
"steps": [
{
@@ -5799,10 +5799,10 @@ update t5, t6 set t6.d=t6.d+t5.c+4-t5.c-
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
delete t6 from t5, t6 where d>7000;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete t6 from t5, t6 where d>7000 {
"steps": [
{
@@ -5960,10 +5960,10 @@ delete t6 from t5, t6 where d>7000 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=2,optimizer_trace_limit=2;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1;
1
1
@@ -5980,7 +5980,7 @@ select 5;
5
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 2 {
"steps": [
{
@@ -5994,7 +5994,7 @@ select 2 {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
select 2 {
"steps": [
{
@@ -6022,10 +6022,10 @@ select 2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=-2,optimizer_trace_limit=2;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 1;
1
1
@@ -6042,7 +6042,7 @@ select 5;
5
5
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select 5 {
"steps": [
{
@@ -6056,7 +6056,7 @@ select 5 {
} /* join_preparation */
}
] /* steps */
-} 0
+} 0 0
select 5 {
"steps": [
{
@@ -6084,10 +6084,10 @@ select 5 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace_offset=default,optimizer_trace_limit=default;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
create table t1 (
id char(16) not null default '',
data int not null
@@ -6111,281 +6111,35 @@ select f1()|
f1()
3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
+} 0 0
select s, f1() from t2 order by s desc|
s f1()
c 3
b 3
a 3
select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
+} 0 0
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
-select sum(data) into ret from t1 {
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+freturn 3 ret@0 {
"steps": [
- {
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "records_estimation": [
- {
- "database": "test",
- "table": "t1",
- "table_scan": {
- "records": 2,
- "cost": 2
- } /* table_scan */
- }
- ] /* 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.0154,
- "chosen": true
- }
- ] /* considered_access_paths */
- } /* best_access_path */,
- "cost_for_plan": 2.4154,
- "records_for_plan": 2,
- "chosen": true
- }
- ] /* considered_execution_plans */
- },
- {
- "attaching_conditions_to_tables": {
- "original_condition": null,
- "attached_conditions_computation": [
- ] /* attached_conditions_computation */,
- "attached_conditions_summary": [
- {
- "database": "test",
- "table": "t1",
- "attached": null
- }
- ] /* attached_conditions_summary */
- } /* attaching_conditions_to_tables */
- },
- {
- "refine_plan": [
- {
- "database": "test",
- "table": "t1",
- "scan_type": "table"
- }
- ] /* refine_plan */
- }
- ] /* steps */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
- }
] /* steps */
-} 0
-set optimizer_trace_offset=-7, optimizer_trace_limit=7|
-select @@optimizer_trace_offset, @@optimizer_trace_limit|
-@@optimizer_trace_offset @@optimizer_trace_limit
--7 7
+} 0 0
+set optimizer_trace_offset=-20, optimizer_trace_limit=20|
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
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from t6 where d in (select f1() from t2 where s="c") {
"steps": [
{
@@ -6415,15 +6169,47 @@ select * from t6 where d in (select f1()
}
] /* steps */
} /* join_preparation */
- },
+ }
+ ] /* steps */
+} 0 0
+select * from t6 where d in (select f1() from t2 where s="c") {
+ "steps": [
{
- "join_optimization": {
+ "join_preparation": {
"select#": 1,
"steps": [
{
- "transformation": {
+ "join_preparation": {
"select#": 2,
- "from": "IN (SELECT)",
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = 'c')"
+ },
+ {
+ "transformation": {
+ "select#": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ } /* transformation */
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d` from `test`.`t6` where `test`.`t6`.`d` in (/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = 'c'))"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "transformation": {
+ "select#": 2,
+ "from": "IN (SELECT)",
"to": "semijoin",
"chosen": true
} /* transformation */
@@ -6762,11 +6548,1260 @@ select * from t6 where d in (select f1()
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+select count(*) from information_schema.OPTIMIZER_TRACE|
+count(*)
+12
+set optimizer_trace_offset=3, optimizer_trace_limit=1|
+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 INSUFFICIENT_PRIVILEGES
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+create procedure p1(arg char(1))
+begin
+declare res int;
+select d into res from t6 where d in (select f1() from t2 where s=arg);
+select d+1 into res from t6 where d=res+1;
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
+call p1("c")|
+Warnings:
+Warning 1329 No data - zero rows fetched, selected, or processed
+select * from information_schema.OPTIMIZER_TRACE|
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+call p1("c") {
+ "steps": [
+ ] /* steps */
+} 0 0
+set res@1 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 2,
+ "steps": [
+ {
+ "expanded_query": "/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = arg@0)"
+ },
+ {
+ "transformation": {
+ "select#": 2,
+ "from": "IN (SELECT)",
+ "to": "semijoin",
+ "chosen": true
+ } /* transformation */
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d` from `test`.`t6` where `test`.`t6`.`d` in (/* select#2 */ select `f1`() from `test`.`t2` where (`test`.`t2`.`s` = arg@0))"
+ }
+ ] /* 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` = arg@0) and (`test`.`t6`.`d` = `f1`()))",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "(1 and multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "(1 and multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "(multiple equal(arg@0, `test`.`t2`.`s`) and multiple equal(`f1`(), `test`.`t6`.`d`))"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "database": "test",
+ "table": "t6",
+ "field": "d",
+ "equals": "`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 */,
+ "setup_range_conditions": [
+ ] /* setup_range_conditions */,
+ "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.6212,
+ "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.6212,
+ "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": 5.8289,
+ "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.2,
+ "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.8213,
+ "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.2213,
+ "records": 1,
+ "chosen": true
+ },
+ {
+ "strategy": "MaterializationLookup",
+ "cost": 4.0212,
+ "records": 1,
+ "duplicate_tables_left": false,
+ "chosen": false
+ },
+ {
+ "strategy": "DuplicatesWeedout",
+ "cost": 3.8213,
+ "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` = arg@0))",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t6",
+ "attached": null
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "attached": "((`test`.`t6`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t6"
+ },
+ {
+ "database": "test",
+ "table": "t2",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ {
+ "database": "test",
+ "table": "t6",
+ "field": "d",
+ "equals": "(res@1 + 1)",
+ "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 */,
+ "setup_range_conditions": [
+ {
+ "impossible_condition": {
+ "cause": "comparison_with_null_always_false"
+ } /* impossible_condition */
+ }
+ ] /* setup_range_conditions */,
+ "impossible_range": true
+ } /* range_analysis */,
+ "records": 0,
+ "cause": "impossible_where_condition"
+ }
+ ] /* records_estimation */
+ }
+ ] /* steps */,
+ "empty_result": {
+ "cause": "no matching row in const table"
+ } /* empty_result */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+create trigger trg1 before insert on t2 for each row
+begin
+set new.s=f1();
+end|
+set optimizer_trace_offset=0, optimizer_trace_limit=100|
+insert into t2 select d,100,200 from t6 where d is not null|
+select * from information_schema.OPTIMIZER_TRACE|
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+insert into t2 select d,100,200 from t6 where d is not null {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d`,100 AS `100`,200 AS `200` from `test`.`t6` where (`test`.`t6`.`d` is not null)"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ }
+ ] /* steps */
+} 0 0
+insert into t2 select d,100,200 from t6 where d is not null {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `test`.`t6`.`d` AS `d`,100 AS `100`,200 AS `200` from `test`.`t6` where (`test`.`t6`.`d` is not null)"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "condition_processing": {
+ "condition": "WHERE",
+ "original_condition": "(`test`.`t6`.`d` is not null)",
+ "steps": [
+ {
+ "transformation": "equality_propagation",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ },
+ {
+ "transformation": "constant_propagation",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ },
+ {
+ "transformation": "trivial_condition_removal",
+ "resulting_condition": "(`test`.`t6`.`d` is not null)"
+ }
+ ] /* steps */
+ } /* condition_processing */
+ },
+ {
+ "ref_optimizer_key_uses": [
+ ] /* 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 */,
+ "setup_range_conditions": [
+ ] /* setup_range_conditions */,
+ "group_index_range": {
+ "chosen": false,
+ "cause": "not_group_by_or_distinct"
+ } /* group_index_range */,
+ "analyzing_range_alternatives": {
+ "range_scan_alternatives": [
+ {
+ "index": "d",
+ "ranges": [
+ "NULL < d"
+ ] /* ranges */,
+ "index_only": true,
+ "records": 4,
+ "cost": 1.8798,
+ "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": "t6",
+ "best_access_path": {
+ "considered_access_paths": [
+ {
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 4,
+ "cost": 2.0068,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.8068,
+ "records_for_plan": 4,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t6`.`d` is not null)",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t6",
+ "attached": "(`test`.`t6`.`d` is not null)"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t6",
+ "scan_type": "index"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
+insert into t1 values("z",0) {
+ "steps": [
+ ] /* steps */
+} 0 0
+delete from t1 where id="z" {
+ "steps": [
+ {
+ "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": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select sum(`test`.`t1`.`data`) AS `sum(data)` from `test`.`t1`"
+ }
+ ] /* steps */
+ } /* join_preparation */
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ {
+ "records_estimation": [
+ {
+ "database": "test",
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
+ }
+ ] /* 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.0154,
+ "chosen": true
+ }
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
+ }
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": null,
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": null
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
+ }
+ ] /* steps */
+ } /* join_optimization */
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ] /* steps */
+ } /* join_execution */
+ }
+ ] /* steps */
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -6780,7 +7815,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -6865,11 +7900,23 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -6883,7 +7930,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -6968,135 +8015,37 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
-set optimizer_trace_offset=2, optimizer_trace_limit=1|
-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
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set_trigger_field NEW.s:=`f1`() {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
-set optimizer_trace_offset=default, optimizer_trace_limit=default|
-create procedure p1(arg char(1))
-begin
-declare res int;
-select d into res from t6 where d in (select f1() from t2 where s=arg);
-select d+1 into res from t6 where d=res+1;
-end|
-call p1("c")|
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
-select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
-select d+1 into res from t6 where d= NAME_CONST('res',NULL)+1 {
+} 0 0
+delete from t1 where id="z" {
"steps": [
{
- "join_preparation": {
- "select#": 1,
- "steps": [
- {
- "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
- }
- ] /* steps */
- } /* join_preparation */
- },
- {
- "join_optimization": {
- "select#": 1,
- "steps": [
- {
- "condition_processing": {
- "condition": "WHERE",
- "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
- "steps": [
- {
- "transformation": "equality_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- },
- {
- "transformation": "constant_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- },
- {
- "transformation": "trivial_condition_removal",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
- }
- ] /* steps */
- } /* condition_processing */
- },
- {
- "ref_optimizer_key_uses": [
- {
- "database": "test",
- "table": "t6",
- "field": "d",
- "equals": "(res@1 + 1)",
- "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 */,
- "setup_range_conditions": [
- {
- "impossible_condition": {
- "cause": "comparison_with_null_always_false"
- } /* impossible_condition */
- }
- ] /* setup_range_conditions */,
- "impossible_range": true
- } /* range_analysis */,
- "records": 0,
- "cause": "impossible_where_condition"
- }
- ] /* records_estimation */
- }
- ] /* steps */,
- "empty_result": {
- "cause": "no matching row in const table"
- } /* empty_result */
- } /* join_optimization */
- },
- {
- "join_execution": {
- "select#": 1,
- "steps": [
- ] /* steps */
- } /* join_execution */
+ "database": "test",
+ "table": "t1",
+ "range_analysis": {
+ "table_scan": {
+ "records": 3,
+ "cost": 4.7154
+ } /* table_scan */
+ } /* range_analysis */
}
] /* steps */
-} 0
-create trigger trg1 before insert on t2 for each row
-begin
-set new.s=f1();
-end|
-insert into t2 select d,100,200 from t6 where d is not null|
-select * from information_schema.OPTIMIZER_TRACE|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7181,7 +8130,11 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
select * from t2|
s i d
a 1 1
@@ -7191,14 +8144,15 @@ c 3 3
3 100 200
3 100 200
3 100 200
-prepare stmt from 'call p1(?)';
-select QUERY from information_schema.OPTIMIZER_TRACE;
-QUERY
-call p1(?)
+prepare stmt from 'select count(*) from t1 where t1.data=?';
set @param="c";
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
+count(*)
+0
+select count(*) from information_schema.OPTIMIZER_TRACE;
+count(*)
+1
select TRACE into @trace from information_schema.OPTIMIZER_TRACE;
select @trace;
@trace
@@ -7209,7 +8163,7 @@ select @trace;
"select#": 1,
"steps": [
{
- "expanded_query": "/* select#1 */ select (`test`.`t6`.`d` + 1) AS `d+1` from `test`.`t6` where (`test`.`t6`.`d` = (res@1 + 1))"
+ "expanded_query": "/* select#1 */ select count(0) AS `count(*)` from `test`.`t1` where (`test`.`t1`.`data` = 'c')"
}
] /* steps */
} /* join_preparation */
@@ -7221,76 +8175,85 @@ select @trace;
{
"condition_processing": {
"condition": "WHERE",
- "original_condition": "(`test`.`t6`.`d` = (res@1 + 1))",
+ "original_condition": "(`test`.`t1`.`data` = 'c')",
"steps": [
{
"transformation": "equality_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
},
{
"transformation": "constant_propagation",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
},
{
"transformation": "trivial_condition_removal",
- "resulting_condition": "multiple equal((res@1 + 1), `test`.`t6`.`d`)"
+ "resulting_condition": "(`test`.`t1`.`data` = 'c')"
}
] /* steps */
} /* condition_processing */
},
{
"ref_optimizer_key_uses": [
+ ] /* ref_optimizer_key_uses */
+ },
+ {
+ "records_estimation": [
{
"database": "test",
- "table": "t6",
- "field": "d",
- "equals": "(res@1 + 1)",
- "null_rejecting": false
+ "table": "t1",
+ "table_scan": {
+ "records": 2,
+ "cost": 2
+ } /* table_scan */
}
- ] /* ref_optimizer_key_uses */
+ ] /* records_estimation */
},
{
- "records_estimation": [
+ "considered_execution_plans": [
{
"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 */,
- "setup_range_conditions": [
+ "table": "t1",
+ "best_access_path": {
+ "considered_access_paths": [
{
- "impossible_condition": {
- "cause": "comparison_with_null_always_false"
- } /* impossible_condition */
+ "access_type": "scan",
+ "using_join_cache": true,
+ "records": 2,
+ "cost": 2.0154,
+ "chosen": true
}
- ] /* setup_range_conditions */,
- "impossible_range": true
- } /* range_analysis */,
- "records": 0,
- "cause": "impossible_where_condition"
+ ] /* considered_access_paths */
+ } /* best_access_path */,
+ "cost_for_plan": 2.4154,
+ "records_for_plan": 2,
+ "chosen": true
}
- ] /* records_estimation */
+ ] /* considered_execution_plans */
+ },
+ {
+ "attaching_conditions_to_tables": {
+ "original_condition": "(`test`.`t1`.`data` = 'c')",
+ "attached_conditions_computation": [
+ ] /* attached_conditions_computation */,
+ "attached_conditions_summary": [
+ {
+ "database": "test",
+ "table": "t1",
+ "attached": "(`test`.`t1`.`data` = 'c')"
+ }
+ ] /* attached_conditions_summary */
+ } /* attaching_conditions_to_tables */
+ },
+ {
+ "refine_plan": [
+ {
+ "database": "test",
+ "table": "t1",
+ "scan_type": "table"
+ }
+ ] /* refine_plan */
}
- ] /* steps */,
- "empty_result": {
- "cause": "no matching row in const table"
- } /* empty_result */
+ ] /* steps */
} /* join_optimization */
},
{
@@ -7302,15 +8265,19 @@ select @trace;
}
] /* steps */
}
+set optimizer_trace_offset=0, optimizer_trace_limit=100;
execute stmt using @param;
-Warnings:
-Warning 1329 No data - zero rows fetched, selected, or processed
+count(*)
+0
+select count(*) from information_schema.OPTIMIZER_TRACE;
+count(*)
+1
select TRACE into @trace2 from information_schema.OPTIMIZER_TRACE;
select @trace=@trace2;
@trace=@trace2
1
drop procedure p1;
-create table optt like information_schema.OPTIMIZER_TRACE;
+create temporary table optt like information_schema.OPTIMIZER_TRACE;
create procedure p1(arg char(1))
begin
declare res int;
@@ -7328,7 +8295,7 @@ call p1("c")|
Warnings:
Warning 1329 No data - zero rows fetched, selected, or processed
select * from optt|
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select d into res from t6 where d in (select f1() from t2 where s= NAME_CONST('arg',_latin1'c' COLLATE 'latin1_swedish_ci')) {
"steps": [
{
@@ -7670,11 +8637,15 @@ select d into res from t6 where d in (se
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -7688,7 +8659,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7773,11 +8744,19 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
+set ret@0 NULL {
+ "steps": [
+ ] /* steps */
+} 0 0
insert into t1 values("z",0) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from t1 where id="z" {
"steps": [
{
@@ -7791,7 +8770,7 @@ delete from t1 where id="z" {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
select sum(data) into ret from t1 {
"steps": [
{
@@ -7876,12 +8855,16 @@ select sum(data) into ret from t1 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
+freturn 3 ret@0 {
+ "steps": [
+ ] /* steps */
+} 0 0
select @@optimizer_trace|
@@optimizer_trace
enabled=off,end_marker=on,one_line=off
set optimizer_trace="enabled=on";
-drop table optt;
+drop temporary table optt;
drop function f1;
drop procedure p1;
drop trigger trg1;
@@ -7890,7 +8873,7 @@ explain select * from v1 where id="b";
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from v1 where id="b" {
"steps": [
{
@@ -8008,17 +8991,17 @@ explain select * from v1 where id="b" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
insert into v1 values("z", 100);
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
insert into v1 values("z", 100) {
"steps": [
] /* steps */
-} 0
+} 0 0
delete from v1 where data=100;
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
delete from v1 where data=100 {
"steps": [
{
@@ -8032,7 +9015,7 @@ delete from v1 where data=100 {
} /* range_analysis */
}
] /* steps */
-} 0
+} 0 0
drop view v1;
create view v1 as select * from t1 where id < "c" limit 2;
explain select * from v1 where id="b";
@@ -8040,7 +9023,7 @@ id select_type table type possible_keys
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 Using where
2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using where
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
explain select * from v1 where id="b" {
"steps": [
{
@@ -8270,14 +9253,14 @@ explain select * from v1 where id="b" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop view v1;
select * from information_schema.session_variables where
VARIABLE_NAME="optimizer_trace";
VARIABLE_NAME VARIABLE_VALUE
OPTIMIZER_TRACE enabled=on,end_marker=on,one_line=off
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select * from information_schema.session_variables where
VARIABLE_NAME="optimizer_trace" {
"steps": [
@@ -8387,7 +9370,7 @@ VARIABLE_NAME="optimizer_trace" {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set optimizer_trace="end_marker=off";
select 1 union select 2;
1
@@ -8532,7 +9515,7 @@ 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,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,materialization=on,semijoin=on,loosescan=on,firstmatch=on
select * from information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
select "abc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111def" as col {
"steps": [
{
@@ -8560,7 +9543,7 @@ select "abc11111111111111111111111111111
}
}
]
-} 0
+} 0 0
drop table t1,t2;
DROP TABLE t5,t6;
set optimizer_trace=default;
=== modified file 'mysql-test/r/optimizer_trace_range_no_prot.result'
--- a/mysql-test/r/optimizer_trace_range_no_prot.result 2011-04-06 09:19:23 +0000
+++ b/mysql-test/r/optimizer_trace_range_no_prot.result 2011-05-04 20:53:28 +0000
@@ -40,7 +40,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range i2 i2 4 NULL 47 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020 {
"steps": [
{
@@ -234,7 +234,7 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features="range_optimizer=off";
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020;
@@ -242,7 +242,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range i2 i2 4 NULL 47 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020 {
"steps": [
{
@@ -371,7 +371,7 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features="range_optimizer=on";
EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
@@ -379,7 +379,7 @@ id select_type table type possible_keys
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 45 Using sort_union(i1,i2); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020 {
"steps": [
{
@@ -611,14 +611,14 @@ EXPLAIN SELECT * FROM t1 WHERE key1 < 3
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL i2_1 4 NULL 103 Using index for group-by
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2 {
"steps": [
{
@@ -808,13 +808,13 @@ EXPLAIN SELECT key2, MIN(key2_1) FROM t2
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT DISTINCT key2 FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL i2_1 4 NULL 103 Using index for group-by
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT DISTINCT key2 FROM t2 {
"steps": [
{
@@ -1004,7 +1004,7 @@ EXPLAIN SELECT DISTINCT key2 FROM t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT key2, MIN(key2_1) FROM t2
WHERE key2 = 5 or key2 = 4 or key2 = 3 or key2 = 2 or key2 = 1
@@ -1013,7 +1013,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range i2_1,i2_2 i2_1 4 NULL 47 Using where; Using index
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT key2, MIN(key2_1) FROM t2
WHERE key2 = 5 or key2 = 4 or key2 = 3 or key2 = 2 or key2 = 1
GROUP BY key2 {
@@ -1279,14 +1279,14 @@ GROUP BY key2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref i2_1,i2_2 i2_1 4 const 10 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5) {
"steps": [
{
@@ -1500,14 +1500,14 @@ EXPLAIN SELECT * FROM t2 WHERE key2 = 1
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null {
"steps": [
{
@@ -1774,14 +1774,14 @@ EXPLAIN SELECT * FROM t1 WHERE key2=10 O
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL i2_1,i2_2 NULL NULL NULL 1024 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2 {
"steps": [
{
@@ -1928,14 +1928,14 @@ EXPLAIN SELECT * FROM t2 WHERE key2_1 <
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range PRIMARY,i1b PRIMARY 8 NULL 1 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10 {
"steps": [
{
@@ -2137,7 +2137,7 @@ EXPLAIN SELECT * FROM t2 WHERE key1a = 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE (key1a = 5 and key1b < 10 and key1b > 2) or
(key1a = 4 and key1b < 7 and key1b > 3);
@@ -2145,7 +2145,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range PRIMARY,i1b PRIMARY 8 NULL 2 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE (key1a = 5 and key1b < 10 and key1b > 2) or
(key1a = 4 and key1b < 7 and key1b > 3) {
"steps": [
@@ -2338,7 +2338,7 @@ EXPLAIN SELECT * FROM t2 WHERE (key1a =
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE (key1b < 10 and key1b > 7) and
(key1a = 4 or key1a = 5);
@@ -2346,7 +2346,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range PRIMARY,i1b i1b 4 NULL 2 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE (key1b < 10 and key1b > 7) and
(key1a = 4 or key1a = 5) {
"steps": [
@@ -2537,14 +2537,14 @@ EXPLAIN SELECT * FROM t2 WHERE (key1b <
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL i1,i2 NULL NULL NULL 1024 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2) {
"steps": [
{
@@ -2752,7 +2752,7 @@ EXPLAIN SELECT * FROM t1 WHERE (key1 > 1
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT STRAIGHT_JOIN * FROM t1, t2
WHERE t1.key1=t2.key1a AND t1.key2 > 1020;
@@ -2761,7 +2761,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.key1 10
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT STRAIGHT_JOIN * FROM t1, t2
WHERE t1.key1=t2.key1a AND t1.key2 > 1020 {
"steps": [
@@ -3014,7 +3014,7 @@ WHERE t1.key1=t2.key1a AND t1.key2 > 102
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
CREATE TABLE t1 (
cola char(3) not null,
@@ -3031,7 +3031,7 @@ id select_type table type possible_keys
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 32 Using intersect(cola,colb); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
"steps": [
{
@@ -3274,14 +3274,14 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref cola cola 3 const 1 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no' {
"steps": [
{
@@ -3455,7 +3455,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1;
CREATE TABLE t1(c INT);
INSERT INTO t1 VALUES (),();
@@ -3470,7 +3470,7 @@ id select_type table type possible_keys
2 DERIVED t2 ALL b NULL NULL NULL 3 Range checked for each record (index map: 0x1)
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT 1 FROM
(SELECT 1 FROM t2,t1 WHERE b < c GROUP BY 1 LIMIT 1) AS d2 {
"steps": [
@@ -3751,7 +3751,7 @@ EXPLAIN SELECT 1 FROM
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SET optimizer_trace_features="greedy_search=off,dynamic_range=off";
EXPLAIN SELECT 1 FROM
@@ -3762,7 +3762,7 @@ id select_type table type possible_keys
2 DERIVED t2 ALL b NULL NULL NULL 3 Range checked for each record (index map: 0x1)
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT 1 FROM
(SELECT 1 FROM t2,t1 WHERE b < c GROUP BY 1 LIMIT 1) AS d2 {
"steps": [
@@ -4009,7 +4009,7 @@ EXPLAIN SELECT 1 FROM
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
CREATE TABLE `t1` (
@@ -4022,7 +4022,7 @@ SELECT * from t1 where topic = all (SELE
mot topic
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * from t1 where topic = all (SELECT topic FROM t1 GROUP BY topic) {
"steps": [
{
@@ -4264,7 +4264,7 @@ SELECT * from t1 where topic = all (SELE
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1;
CREATE TABLE t1 (
@@ -4280,7 +4280,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range k1,k2 k2 5 NULL 2 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE i1 > '2' ORDER BY i1, i2 {
"steps": [
{
@@ -4505,14 +4505,14 @@ EXPLAIN SELECT * FROM t1 WHERE i1 > '2'
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE i1 >= '1' ORDER BY i1 DESC;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index k1,k2 k1 5 NULL 2 Using where; Using index
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE i1 >= '1' ORDER BY i1 DESC {
"steps": [
{
@@ -5067,6 +5067,6 @@ EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1;
=== modified file 'mysql-test/r/optimizer_trace_range_ps_prot.result'
--- a/mysql-test/r/optimizer_trace_range_ps_prot.result 2011-04-06 09:19:23 +0000
+++ b/mysql-test/r/optimizer_trace_range_ps_prot.result 2011-05-04 20:53:28 +0000
@@ -40,7 +40,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range i2 i2 4 NULL 47 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020 {
"steps": [
{
@@ -234,7 +234,7 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features="range_optimizer=off";
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020;
@@ -242,7 +242,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range i2 i2 4 NULL 47 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2 < 5 OR key2 > 1020 {
"steps": [
{
@@ -371,7 +371,7 @@ EXPLAIN SELECT * FROM t1 WHERE key2 < 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
set @@optimizer_trace_features="range_optimizer=on";
EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
@@ -379,7 +379,7 @@ id select_type table type possible_keys
1 SIMPLE t1 index_merge i1,i2 i1,i2 4,4 NULL 45 Using sort_union(i1,i2); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020 {
"steps": [
{
@@ -611,14 +611,14 @@ EXPLAIN SELECT * FROM t1 WHERE key1 < 3
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL i2_1 4 NULL 103 Using index for group-by
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2 {
"steps": [
{
@@ -808,13 +808,13 @@ EXPLAIN SELECT key2, MIN(key2_1) FROM t2
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT DISTINCT key2 FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL i2_1 4 NULL 103 Using index for group-by
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT DISTINCT key2 FROM t2 {
"steps": [
{
@@ -1004,7 +1004,7 @@ EXPLAIN SELECT DISTINCT key2 FROM t2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT key2, MIN(key2_1) FROM t2
WHERE key2 = 5 or key2 = 4 or key2 = 3 or key2 = 2 or key2 = 1
@@ -1013,7 +1013,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range i2_1,i2_2 i2_1 4 NULL 47 Using where; Using index
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT key2, MIN(key2_1) FROM t2
WHERE key2 = 5 or key2 = 4 or key2 = 3 or key2 = 2 or key2 = 1
GROUP BY key2 {
@@ -1279,14 +1279,14 @@ GROUP BY key2 {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref i2_1,i2_2 i2_1 4 const 10 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5) {
"steps": [
{
@@ -1500,14 +1500,14 @@ EXPLAIN SELECT * FROM t2 WHERE key2 = 1
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i2,i3,i4 i2,i3 4,4 NULL 2 Using union(i2,i3); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null {
"steps": [
{
@@ -1774,14 +1774,14 @@ EXPLAIN SELECT * FROM t1 WHERE key2=10 O
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL i2_1,i2_2 NULL NULL NULL 1024 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2 {
"steps": [
{
@@ -1928,14 +1928,14 @@ EXPLAIN SELECT * FROM t2 WHERE key2_1 <
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range PRIMARY,i1b PRIMARY 8 NULL 1 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE key1a = 5 and key1b < 10 {
"steps": [
{
@@ -2137,7 +2137,7 @@ EXPLAIN SELECT * FROM t2 WHERE key1a = 5
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE (key1a = 5 and key1b < 10 and key1b > 2) or
(key1a = 4 and key1b < 7 and key1b > 3);
@@ -2145,7 +2145,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range PRIMARY,i1b PRIMARY 8 NULL 2 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE (key1a = 5 and key1b < 10 and key1b > 2) or
(key1a = 4 and key1b < 7 and key1b > 3) {
"steps": [
@@ -2338,7 +2338,7 @@ EXPLAIN SELECT * FROM t2 WHERE (key1a =
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t2 WHERE (key1b < 10 and key1b > 7) and
(key1a = 4 or key1a = 5);
@@ -2346,7 +2346,7 @@ id select_type table type possible_keys
1 SIMPLE t2 range PRIMARY,i1b i1b 4 NULL 2 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t2 WHERE (key1b < 10 and key1b > 7) and
(key1a = 4 or key1a = 5) {
"steps": [
@@ -2537,14 +2537,14 @@ EXPLAIN SELECT * FROM t2 WHERE (key1b <
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL i1,i2 NULL NULL NULL 1024 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2 > 2) {
"steps": [
{
@@ -2752,7 +2752,7 @@ EXPLAIN SELECT * FROM t1 WHERE (key1 > 1
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT STRAIGHT_JOIN * FROM t1, t2
WHERE t1.key1=t2.key1a AND t1.key2 > 1020;
@@ -2761,7 +2761,7 @@ id select_type table type possible_keys
1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.key1 10
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT STRAIGHT_JOIN * FROM t1, t2
WHERE t1.key1=t2.key1a AND t1.key2 > 1020 {
"steps": [
@@ -3014,7 +3014,7 @@ WHERE t1.key1=t2.key1a AND t1.key2 > 102
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
CREATE TABLE t1 (
cola char(3) not null,
@@ -3031,7 +3031,7 @@ id select_type table type possible_keys
1 SIMPLE t1 index_merge cola,colb cola,colb 3,3 NULL 32 Using intersect(cola,colb); Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar' {
"steps": [
{
@@ -3274,14 +3274,14 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref cola cola 3 const 1 Using index condition
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE cola = 'f\no' {
"steps": [
{
@@ -3455,7 +3455,7 @@ EXPLAIN SELECT * FROM t1 WHERE cola = 'f
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1;
CREATE TABLE t1(c INT);
INSERT INTO t1 VALUES (),();
@@ -3470,7 +3470,7 @@ id select_type table type possible_keys
2 DERIVED t2 ALL b NULL NULL NULL 3 Range checked for each record (index map: 0x1)
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT 1 FROM
(SELECT 1 FROM t2,t1 WHERE b < c GROUP BY 1 LIMIT 1) AS d2 {
"steps": [
@@ -3751,7 +3751,7 @@ EXPLAIN SELECT 1 FROM
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SET optimizer_trace_features="greedy_search=off,dynamic_range=off";
EXPLAIN SELECT 1 FROM
@@ -3762,7 +3762,7 @@ id select_type table type possible_keys
2 DERIVED t2 ALL b NULL NULL NULL 3 Range checked for each record (index map: 0x1)
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT 1 FROM
(SELECT 1 FROM t2,t1 WHERE b < c GROUP BY 1 LIMIT 1) AS d2 {
"steps": [
@@ -4009,7 +4009,7 @@ EXPLAIN SELECT 1 FROM
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
CREATE TABLE `t1` (
@@ -4022,7 +4022,7 @@ SELECT * from t1 where topic = all (SELE
mot topic
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT * from t1 where topic = all (SELECT topic FROM t1 GROUP BY topic) {
"steps": [
{
@@ -4256,7 +4256,7 @@ SELECT * from t1 where topic = all (SELE
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
drop table t1;
CREATE TABLE t1 (
@@ -4272,7 +4272,7 @@ id select_type table type possible_keys
1 SIMPLE t1 range k1,k2 k2 5 NULL 2 Using where
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT * FROM t1 WHERE i1 > '2' ORDER BY i1, i2 {
"steps": [
{
@@ -4497,14 +4497,14 @@ EXPLAIN SELECT * FROM t1 WHERE i1 > '2'
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE i1 >= '1' ORDER BY i1 DESC;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index k1,k2 k1 5 NULL 2 Using where; Using index
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE i1 >= '1' ORDER BY i1 DESC {
"steps": [
{
@@ -5059,6 +5059,6 @@ EXPLAIN SELECT DISTINCT i1 FROM t1 WHERE
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1;
=== added file 'mysql-test/r/optimizer_trace_security_no_prot.result'
--- a/mysql-test/r/optimizer_trace_security_no_prot.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_trace_security_no_prot.result 2011-05-04 20:53:28 +0000
@@ -0,0 +1,1074 @@
+set @old_size = @@global.optimizer_trace_max_mem_size;
+set global optimizer_trace_max_mem_size=1048576;
+select user();
+user()
+root@localhost
+create database somedb;
+use somedb;
+create table t1(a varchar(100));
+insert into t1 values("first");
+create table t2(a varchar(100));
+insert into t2 values("first");
+create table t3(a varchar(100));
+insert into t3 values("first");
+create procedure p1() sql security definer
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end|
+create sql security definer view v1 as select * from t1;
+create user user1@localhost identified by '';
+grant all on *.* to user1@localhost with grant option;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'user1'@'localhost' WITH GRANT OPTION
+
+# ==========================================================
+# Part A.
+# Test that security context changes are allowed when, and only
+# when, invoker has all global privileges.
+# ==========================================================
+
+# Because invoker has all global privileges, all traces are visible:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1047 0
+insert into t1 values(current_user()) 20 0
+# this SET always purges all remembered traces
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+root@localhost
+root@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 2163 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+insert into t3 select * from t3 1039 0
+
+# Show that really all global privileges are needed: let root
+# revoke just one from user1. Because user1 does not have all global
+# privileges anymore, security context changes are forbidden,
+# thus there is no trace.
+
+select user();
+user()
+root@localhost
+revoke shutdown on *.* from user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'user1'@'localhost' WITH GRANT OPTION
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# In CALL we execute stored procedure and notice a security
+# context change. The context change is probably only relevant
+# for substatements, but we still hide CALL. This is to be
+# consistent with what we do when routine body should not be
+# exposed. And it also feels safer to disable I_S output as
+# soon as possible.
+# Ps-protocol-specific note: mysqltest uses normal protocol for CALL
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+root@localhost
+root@localhost
+root@localhost
+root@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+
+# Verify that user1 cannot circumvent security checks by
+# setting @@optimizer_trace_offset so that I_S output is disabled
+# before the object (routine) is checked, and enabled in the
+# middle of object usage, when 'offset' is passed.
+
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+# Even though the routine's execution started before
+# 'offset', it detected the security context changes. So the
+# trace of CALL gets the "missing privilege" mark but we don't
+# see it as CALL was before 'offset'.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+
+# Finally, verify that if the routine's definer does modify
+# @@optimizer_trace from "enabled=off" to "enabled=on", in the
+# body of the routine, then tracing works. This is no security
+# issue, as it was done by the routine's definer.
+
+select user();
+user()
+root@localhost
+create procedure p2() sql security definer
+begin
+declare b int;
+set optimizer_trace="enabled=on";
+select 22 into b from dual;
+end|
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+# Variable is as set by the routine
+select @@optimizer_trace;
+@@optimizer_trace
+enabled=on,end_marker=off,one_line=off
+
+# ==========================================================
+# Part B.
+# Do same tests but with SQL SECURITY INVOKER objects, to verify that
+# the restriction on security context changes is not present.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+alter procedure p1 sql security invoker;
+alter function f1 sql security invoker;
+alter sql security invoker view v1 as select * from t1;
+# Triggers cannot be SQL SECURITY INVOKER so we don't test
+# them here.
+alter procedure p2 sql security invoker;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1047 0
+insert into t1 values(current_user()) 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 2163 0
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+# SELECT substatement is traced (no security context change)
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+select @@optimizer_trace;
+@@optimizer_trace
+enabled=on,end_marker=off,one_line=off
+
+# ==========================================================
+# Part C.
+# User1 got traces. Determine the minimum set of privileges he
+# needed for that.
+# ==========================================================
+
+drop procedure p2;
+select user();
+user()
+root@localhost
+revoke all privileges, grant option from user1@localhost;
+# Grant minimum privileges to use the routines and views,
+# without considering optimizer trace:
+grant execute on procedure p1 to user1@localhost;
+grant execute on function f1 to user1@localhost;
+grant select (a) on v1 to user1@localhost;
+# Objects above are SQL SECURITY INVOKER, so invoker needs
+# privileges on objects used internally:
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT SELECT (a), INSERT (a) ON `somedb`.`t1` TO 'user1'@'localhost'
+GRANT SELECT (a) ON `somedb`.`v1` TO 'user1'@'localhost'
+GRANT EXECUTE ON PROCEDURE `somedb`.`p1` TO 'user1'@'localhost'
+GRANT EXECUTE ON FUNCTION `somedb`.`f1` TO 'user1'@'localhost'
+
+# Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# In CALL we execute stored procedure and notice that body should
+# not be exposed. The trace of this CALL would not expose the
+# body. Trace of substatements would. But, due to
+# implementation, CALL is hidden.
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# SELECT is hidden (same reason as for CALL).
+# Ps-protocol-specific note: preparation of SELECT above does not
+# execute f1, so does not risk exposing body, so its trace is
+# visible.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it would expose body of view
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# C.0) Add more privileges:
+
+select user();
+user()
+root@localhost
+# - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+# - for use of routines:
+grant select on mysql.proc to user1@localhost;
+# - for use of view:
+grant select, show view on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1038 0
+insert into t1 values(current_user()) 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
+ SQL SECURITY INVOKER
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t1 limit 1;
+a
+first
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11)
+ SQL SECURITY INVOKER
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 2163 0
+# Trace exposed body of view, and content of t1, which we
+# could see anyway:
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+
+# Now remove each privilege to verify that it was needed:
+# C.1) remove table-level SELECT privilege on t1
+
+select user();
+user()
+root@localhost
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Cannot see those substatements which use t1
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+call p1() {
+ "steps": [
+ ]
+} 0
+set b@0 NULL {
+ "steps": [
+ ]
+} 0
+ 1
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+ 1
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# Cannot see those substatements which use t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+ 0 1
+ 0 1
+freturn 3 36 20 0
+# Trace exposed body of routine, which we could see anyway:
+set optimizer_trace="enabled=off";
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11)
+ SQL SECURITY INVOKER
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace="enabled=on";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# C.2) remove table-level SELECT privilege on mysql.proc
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.1
+grant select on t1 to user1@localhost;
+# And remove a next one:
+revoke select on mysql.proc from user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+# We have no right to see routines' bodies:
+set optimizer_trace="enabled=off";
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+# Verify that optimizer trace does not influence the privilege
+# checking in SHOW CREATE:
+set optimizer_trace="enabled=on";
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Cannot see anything as it would expose body of routine
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+
+# C.3) remove table-level SELECT privilege on view
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.2
+grant select on mysql.proc to user1@localhost;
+# And remove a next one:
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+# Cannot see anything as it might expose some data from columns
+# of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# C.4) remove SHOW VIEW privilege on view
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.3
+grant select on v1 to user1@localhost;
+# And remove a next one:
+revoke show view on v1 from user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=off";
+# We have no right to see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace="enabled=on";
+# Verify that optimizer trace does not influence the privilege
+# checking in SHOW CREATE:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+# Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+
+# ==========================================================
+# Part D.
+# Like Part C, but instead of SQL SECURITY INVOKER objects
+# created by root and used by User1, let's have SQL SECURITY
+# DEFINER objects created and used by User1. Determine the
+# minimum set of privileges he needs for that.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+drop procedure p1;
+drop function f1;
+drop view v1;
+drop trigger trg2;
+revoke all privileges, grant option from user1@localhost;
+# Grant minimum privileges to create and use objects,
+# without considering optimizer trace:
+grant create routine on somedb.* to user1@localhost;
+grant trigger on t2 to user1@localhost;
+grant create view on somedb.* to user1@localhost;
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+grant insert (a) on t2 to user1@localhost;
+grant select (a) on t3 to user1@localhost;
+grant insert (a) on t3 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+create procedure p1() sql security definer
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end|
+create sql security definer view v1 as select * from t1;
+# Creating a view is not enough to be able to SELECT it...
+select user();
+user()
+root@localhost
+grant select (a) on v1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+# Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+ 0 1
+select 22 into b from dual 407 0
+ 0 1
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+ 0 1
+ 0 1
+freturn 3 36 20 0
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`user1`@`localhost` FUNCTION `f1`() RETURNS int(11)
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see anything as it might expose some data from
+# columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+# Also test a query accessing t1 in FROM clause:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+a
+first
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# D.0) Add more privileges:
+
+select user();
+user()
+root@localhost
+# - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+# - for use of view:
+grant select, show view on v1 to user1@localhost;
+# - for use of trigger
+grant select on t2 to user1@localhost;
+grant select on t3 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1038 0
+insert into t1 values(current_user()) 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`user1`@`localhost` PROCEDURE `p1`()
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t1 limit 1;
+a
+first
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`user1`@`localhost` FUNCTION `f1`() RETURNS int(11)
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 2163 0
+# Trace exposed body of view, and content of t1, which we
+# could see anyway:
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`user1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+insert into t3 select * from t3 2020 0
+# Trace exposed body of trigger, and content of t2/t3, which we
+# could see anyway:
+show create trigger trg2;
+Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation
+trg2 CREATE DEFINER=`user1`@`localhost` trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t2, t3 limit 1;
+a a
+first first
+# Trace exposed content of t1 which we could see anyway:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+a
+first
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select a from (select a from t1 where a like "f%") as tt where a like "fi%" 4838 0
+
+# For routines, as they only use t1 and we added only one
+# privilege on t1, we have nothing to remove.
+
+# Now remove each privilege to verify that it was needed for
+# the view.
+# D.1) remove table-level SELECT privilege on v1
+
+select user();
+user()
+root@localhost
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# D.2) remove table-level SHOW VIEW privilege on v1
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.1
+grant select on v1 to user1@localhost;
+# And remove a next one:
+revoke show view on v1 from user1@localhost;
+
+select user();
+user()
+user1@localhost
+# We have no right to see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+
+# D.3) remove table-level SELECT privilege on t1
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.2
+grant show view on v1 to user1@localhost;
+# And remove a next one:
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# Now remove each privilege to verify that it was needed for
+# the trigger:
+# D.4) remove table-level SELECT privilege on t2
+
+select user();
+user()
+root@localhost
+revoke select on t2 from user1@localhost;
+grant select (a) on t2 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see anything as it might expose some data from
+# columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+
+# D.5) remove table-level SELECT privilege on t3
+
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.4
+grant select on t2 to user1@localhost;
+# And remove a next one:
+revoke select on t3 from user1@localhost;
+grant select (a) on t3 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see substatement as it might expose some data from
+# columns of t3
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+ 0 1
+
+# Cleanup
+select user();
+user()
+root@localhost
+drop user user1@localhost;
+
+# ==========================================================
+# Part E.
+# Misc tests.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+drop view v1;
+create sql security definer view v1 as select * from t1 where 'secret';
+create user user1@localhost identified by '';
+grant create, insert, select on somedb.* to user1@localhost;
+grant create routine on somedb.* to user1@localhost;
+
+select user();
+user()
+user1@localhost
+user1 cannot see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+user1 creates a procedure
+create procedure proc() sql security definer
+begin
+set optimizer_trace="enabled=on";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1 limit 0;
+create table leak select * from information_schema.optimizer_trace;
+set optimizer_trace="enabled=off";
+end|
+select user();
+user()
+root@localhost
+root runs procedure, without fear of risk as it is SQL SECURITY DEFINER
+call proc();
+a
+
+select user();
+user()
+user1@localhost
+user1 cannot see view's body:
+select * from leak;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+
+# Cleanup
+select user();
+user()
+root@localhost
+drop database somedb;
+drop user user1@localhost;
+set @@global.optimizer_trace_max_mem_size = @old_size;
=== added file 'mysql-test/r/optimizer_trace_security_ps_prot.result'
--- a/mysql-test/r/optimizer_trace_security_ps_prot.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/optimizer_trace_security_ps_prot.result 2011-05-04 20:53:28 +0000
@@ -0,0 +1,1146 @@
+set @old_size = @@global.optimizer_trace_max_mem_size;
+set global optimizer_trace_max_mem_size=1048576;
+select user();
+user()
+root@localhost
+create database somedb;
+use somedb;
+create table t1(a varchar(100));
+insert into t1 values("first");
+create table t2(a varchar(100));
+insert into t2 values("first");
+create table t3(a varchar(100));
+insert into t3 values("first");
+create procedure p1() sql security definer
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end|
+create sql security definer view v1 as select * from t1;
+create user user1@localhost identified by '';
+grant all on *.* to user1@localhost with grant option;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'user1'@'localhost' WITH GRANT OPTION
+
+# ==========================================================
+# Part A.
+# Test that security context changes are allowed when, and only
+# when, invoker has all global privileges.
+# ==========================================================
+
+# Because invoker has all global privileges, all traces are visible:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1047 0
+insert into t1 values(current_user()) 20 0
+# this SET always purges all remembered traces
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+root@localhost
+root@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 402 0
+select * from v1 2004 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+insert into t2 values(current_user()) 20 0
+insert into t3 select * from t3 1039 0
+
+# Show that really all global privileges are needed: let root
+# revoke just one from user1. Because user1 does not have all global
+# privileges anymore, security context changes are forbidden,
+# thus there is no trace.
+
+select user();
+user()
+root@localhost
+revoke shutdown on *.* from user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE ON *.* TO 'user1'@'localhost' WITH GRANT OPTION
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# In CALL we execute stored procedure and notice a security
+# context change. The context change is probably only relevant
+# for substatements, but we still hide CALL. This is to be
+# consistent with what we do when routine body should not be
+# exposed. And it also feels safer to disable I_S output as
+# soon as possible.
+# Ps-protocol-specific note: mysqltest uses normal protocol for CALL
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select f1() {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `f1`() AS `f1()`"
+ }
+ ]
+ }
+ }
+ ]
+} 0
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+root@localhost
+root@localhost
+root@localhost
+root@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) {
+ "steps": [
+ ]
+} 0
+ 1
+
+# Verify that user1 cannot circumvent security checks by
+# setting @@optimizer_trace_offset so that I_S output is disabled
+# before the object (routine) is checked, and enabled in the
+# middle of object usage, when 'offset' is passed.
+
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+# Even though the routine's execution started before
+# 'offset', it detected the security context changes. So the
+# trace of CALL gets the "missing privilege" mark but we don't
+# see it as CALL was before 'offset'.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+
+# Finally, verify that if the routine's definer does modify
+# @@optimizer_trace from "enabled=off" to "enabled=on", in the
+# body of the routine, then tracing works. This is no security
+# issue, as it was done by the routine's definer.
+
+select user();
+user()
+root@localhost
+create procedure p2() sql security definer
+begin
+declare b int;
+set optimizer_trace="enabled=on";
+select 22 into b from dual;
+end|
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+# Variable is as set by the routine
+select @@optimizer_trace;
+@@optimizer_trace
+enabled=on,end_marker=off,one_line=off
+
+# ==========================================================
+# Part B.
+# Do same tests but with SQL SECURITY INVOKER objects, to verify that
+# the restriction on security context changes is not present.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+alter procedure p1 sql security invoker;
+alter function f1 sql security invoker;
+alter sql security invoker view v1 as select * from t1;
+# Triggers cannot be SQL SECURITY INVOKER so we don't test
+# them here.
+alter procedure p2 sql security invoker;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1047 0
+insert into t1 values(current_user()) 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 402 0
+select * from v1 2004 0
+set optimizer_trace_offset=2,optimizer_trace_limit=1;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+set optimizer_trace="enabled=off";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p2();
+# SELECT substatement is traced (no security context change)
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+select @@optimizer_trace;
+@@optimizer_trace
+enabled=on,end_marker=off,one_line=off
+
+# ==========================================================
+# Part C.
+# User1 got traces. Determine the minimum set of privileges he
+# needed for that.
+# ==========================================================
+
+drop procedure p2;
+select user();
+user()
+root@localhost
+revoke all privileges, grant option from user1@localhost;
+# Grant minimum privileges to use the routines and views,
+# without considering optimizer trace:
+grant execute on procedure p1 to user1@localhost;
+grant execute on function f1 to user1@localhost;
+grant select (a) on v1 to user1@localhost;
+# Objects above are SQL SECURITY INVOKER, so invoker needs
+# privileges on objects used internally:
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+show grants;
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT SELECT (a), INSERT (a) ON `somedb`.`t1` TO 'user1'@'localhost'
+GRANT SELECT (a) ON `somedb`.`v1` TO 'user1'@'localhost'
+GRANT EXECUTE ON PROCEDURE `somedb`.`p1` TO 'user1'@'localhost'
+GRANT EXECUTE ON FUNCTION `somedb`.`f1` TO 'user1'@'localhost'
+
+# Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# In CALL we execute stored procedure and notice that body should
+# not be exposed. The trace of this CALL would not expose the
+# body. Trace of substatements would. But, due to
+# implementation, CALL is hidden.
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# SELECT is hidden (same reason as for CALL).
+# Ps-protocol-specific note: preparation of SELECT above does not
+# execute f1, so does not risk exposing body, so its trace is
+# visible.
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select f1() {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `f1`() AS `f1()`"
+ }
+ ]
+ }
+ }
+ ]
+} 0
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it would expose body of view
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# C.0) Add more privileges:
+
+select user();
+user()
+root@localhost
+# - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+# - for use of routines:
+grant select on mysql.proc to user1@localhost;
+# - for use of view:
+grant select, show view on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1038 0
+insert into t1 values(current_user()) 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
+ SQL SECURITY INVOKER
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t1 limit 1;
+a
+first
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11)
+ SQL SECURITY INVOKER
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 402 0
+select * from v1 2004 0
+# Trace exposed body of view, and content of t1, which we
+# could see anyway:
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY INVOKER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+
+# Now remove each privilege to verify that it was needed:
+# C.1) remove table-level SELECT privilege on t1
+
+select user();
+user()
+root@localhost
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Cannot see those substatements which use t1
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+call p1() {
+ "steps": [
+ ]
+} 0
+set b@0 NULL {
+ "steps": [
+ ]
+} 0
+ 1
+select 22 into b from dual {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select 22 AS `22`"
+ }
+ ]
+ }
+ },
+ {
+ "join_optimization": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ },
+ {
+ "join_execution": {
+ "select#": 1,
+ "steps": [
+ ]
+ }
+ }
+ ]
+} 0
+ 1
+ 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# Cannot see those substatements which use t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+ 0 1
+ 0 1
+freturn 3 36 20 0
+# Trace exposed body of routine, which we could see anyway:
+set optimizer_trace="enabled=off";
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11)
+ SQL SECURITY INVOKER
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace="enabled=on";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# C.2) remove table-level SELECT privilege on mysql.proc
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.1
+grant select on t1 to user1@localhost;
+# And remove a next one:
+revoke select on mysql.proc from user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+# We have no right to see routines' bodies:
+set optimizer_trace="enabled=off";
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+# Verify that optimizer trace does not influence the privilege
+# checking in SHOW CREATE:
+set optimizer_trace="enabled=on";
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 NULL latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Cannot see anything as it would expose body of routine
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+select f1() {
+ "steps": [
+ {
+ "join_preparation": {
+ "select#": 1,
+ "steps": [
+ {
+ "expanded_query": "/* select#1 */ select `f1`() AS `f1()`"
+ }
+ ]
+ }
+ }
+ ]
+} 0
+ 1
+
+# C.3) remove table-level SELECT privilege on view
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.2
+grant select on mysql.proc to user1@localhost;
+# And remove a next one:
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+# Cannot see anything as it might expose some data from columns
+# of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# C.4) remove SHOW VIEW privilege on view
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in C.3
+grant select on v1 to user1@localhost;
+# And remove a next one:
+revoke show view on v1 from user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=off";
+# We have no right to see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace="enabled=on";
+# Verify that optimizer trace does not influence the privilege
+# checking in SHOW CREATE:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+# Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+ 1
+
+# ==========================================================
+# Part D.
+# Like Part C, but instead of SQL SECURITY INVOKER objects
+# created by root and used by User1, let's have SQL SECURITY
+# DEFINER objects created and used by User1. Determine the
+# minimum set of privileges he needs for that.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+drop procedure p1;
+drop function f1;
+drop view v1;
+drop trigger trg2;
+revoke all privileges, grant option from user1@localhost;
+# Grant minimum privileges to create and use objects,
+# without considering optimizer trace:
+grant create routine on somedb.* to user1@localhost;
+grant trigger on t2 to user1@localhost;
+grant create view on somedb.* to user1@localhost;
+grant select (a) on t1 to user1@localhost;
+grant insert (a) on t1 to user1@localhost;
+grant insert (a) on t2 to user1@localhost;
+grant select (a) on t3 to user1@localhost;
+grant insert (a) on t3 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace="enabled=on";
+create procedure p1() sql security definer
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end|
+create function f1() returns int sql security definer
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end|
+create trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end|
+create sql security definer view v1 as select * from t1;
+# Creating a view is not enough to be able to SELECT it...
+select user();
+user()
+root@localhost
+grant select (a) on v1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+# Those privileges are not enough to see traces:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+# Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+ 0 1
+select 22 into b from dual 407 0
+ 0 1
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+# Can see body of routine (as definer), but not statements using t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+ 0 1
+ 0 1
+freturn 3 36 20 0
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`user1`@`localhost` FUNCTION `f1`() RETURNS int(11)
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see anything as it might expose some data from
+# columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+# Also test a query accessing t1 in FROM clause:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+a
+first
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# D.0) Add more privileges:
+
+select user();
+user()
+root@localhost
+# - for use of t1 in routines and view:
+grant select on t1 to user1@localhost;
+# - for use of view:
+grant select, show view on v1 to user1@localhost;
+# - for use of trigger
+grant select on t2 to user1@localhost;
+grant select on t3 to user1@localhost;
+delete from t1 where a<>"first";
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+call p1();
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+call p1() 20 0
+set b@0 NULL 20 0
+jump_if_not 3(3) (select count(0) from `somedb`.`t1`) 715 0
+select 22 into b from dual 407 0
+select a into b from t1 limit 1 1038 0
+insert into t1 values(current_user()) 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create procedure p1;
+Procedure sql_mode Create Procedure character_set_client collation_connection Database Collation
+p1 CREATE DEFINER=`user1`@`localhost` PROCEDURE `p1`()
+begin
+declare b int;
+if (select count(*) from t1)
+then
+select 22 into b from dual;
+end if;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t1 limit 1;
+a
+first
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select f1();
+f1()
+36
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select f1() 214 0
+select f1() 413 0
+set b@0 NULL 20 0
+select 48 into b from dual 407 0
+select a into b from t1 limit 1 2010 0
+insert into t1 values(current_user()) 20 0
+freturn 3 36 20 0
+# Trace exposed body of routine, and content of t1, which we
+# could see anyway:
+show create function f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 CREATE DEFINER=`user1`@`localhost` FUNCTION `f1`() RETURNS int(11)
+begin
+declare b int;
+select 48 into b from dual;
+select a into b from t1 limit 1;
+insert into t1 values(current_user());
+return 36;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select * from v1 402 0
+select * from v1 2004 0
+# Trace exposed body of view, and content of t1, which we
+# could see anyway:
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`user1`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+insert into t2 values(current_user()) 20 0
+insert into t3 select * from t3 2020 0
+# Trace exposed body of trigger, and content of t2/t3, which we
+# could see anyway:
+show create trigger trg2;
+Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation
+trg2 CREATE DEFINER=`user1`@`localhost` trigger trg2 before insert on t2 for each row
+begin
+insert into t3 select * from t3;
+end latin1 latin1_swedish_ci latin1_swedish_ci
+select * from t2, t3 limit 1;
+a a
+first first
+# Trace exposed content of t1 which we could see anyway:
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select a from (select a from t1 where a like "f%") as tt where a like "fi%";
+a
+first
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+select a from (select a from t1 where a like "f%") as tt where a like "fi%" 613 0
+select a from (select a from t1 where a like "f%") as tt where a like "fi%" 4838 0
+
+# For routines, as they only use t1 and we added only one
+# privilege on t1, we have nothing to remove.
+
+# Now remove each privilege to verify that it was needed for
+# the view.
+# D.1) remove table-level SELECT privilege on v1
+
+select user();
+user()
+root@localhost
+revoke select on v1 from user1@localhost;
+grant select (a) on v1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of v1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# D.2) remove table-level SHOW VIEW privilege on v1
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.1
+grant select on v1 to user1@localhost;
+# And remove a next one:
+revoke show view on v1 from user1@localhost;
+
+select user();
+user()
+user1@localhost
+# We have no right to see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it would expose body of view
+select QUERY, TRACE, INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY TRACE INSUFFICIENT_PRIVILEGES
+ 1
+ 1
+
+# D.3) remove table-level SELECT privilege on t1
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.2
+grant show view on v1 to user1@localhost;
+# And remove a next one:
+revoke select on t1 from user1@localhost;
+grant select (a) on t1 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1;
+a
+first
+user1@localhost
+user1@localhost
+# Cannot see anything as it might expose some data from columns
+# of t1
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# Now remove each privilege to verify that it was needed for
+# the trigger:
+# D.4) remove table-level SELECT privilege on t2
+
+select user();
+user()
+root@localhost
+revoke select on t2 from user1@localhost;
+grant select (a) on t2 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see anything as it might expose some data from
+# columns of t2
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+ 0 1
+ 0 1
+
+# D.5) remove table-level SELECT privilege on t3
+
+
+select user();
+user()
+root@localhost
+# Put back privilege removed in D.4
+grant select on t2 to user1@localhost;
+# And remove a next one:
+revoke select on t3 from user1@localhost;
+grant select (a) on t3 to user1@localhost;
+
+select user();
+user()
+user1@localhost
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+insert into t2 values(current_user());
+# Cannot see substatement as it might expose some data from
+# columns of t3
+select QUERY, length(TRACE), INSUFFICIENT_PRIVILEGES from information_schema.OPTIMIZER_TRACE;
+QUERY length(TRACE) INSUFFICIENT_PRIVILEGES
+insert into t2 values(current_user()) 20 0
+insert into t2 values(current_user()) 20 0
+ 0 1
+
+# Cleanup
+select user();
+user()
+root@localhost
+drop user user1@localhost;
+
+# ==========================================================
+# Part E.
+# Misc tests.
+# ==========================================================
+
+select user();
+user()
+root@localhost
+drop view v1;
+create sql security definer view v1 as select * from t1 where 'secret';
+create user user1@localhost identified by '';
+grant create, insert, select on somedb.* to user1@localhost;
+grant create routine on somedb.* to user1@localhost;
+
+select user();
+user()
+user1@localhost
+user1 cannot see view's body:
+show create view v1;
+ERROR 42000: SHOW VIEW command denied to user 'user1'@'localhost' for table 'v1'
+user1 creates a procedure
+create procedure proc() sql security definer
+begin
+set optimizer_trace="enabled=on";
+set optimizer_trace_offset=0,optimizer_trace_limit=100;
+select * from v1 limit 0;
+create table leak select * from information_schema.optimizer_trace;
+set optimizer_trace="enabled=off";
+end|
+select user();
+user()
+root@localhost
+root runs procedure, without fear of risk as it is SQL SECURITY DEFINER
+call proc();
+a
+
+select user();
+user()
+user1@localhost
+user1 cannot see view's body:
+select * from leak;
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
+
+# Cleanup
+select user();
+user()
+root@localhost
+drop database somedb;
+drop user user1@localhost;
+set @@global.optimizer_trace_max_mem_size = @old_size;
=== modified file 'mysql-test/r/optimizer_trace_subquery_no_prot.result'
--- a/mysql-test/r/optimizer_trace_subquery_no_prot.result 2011-03-01 10:55:27 +0000
+++ b/mysql-test/r/optimizer_trace_subquery_no_prot.result 2011-05-04 20:53:28 +0000
@@ -12,7 +12,7 @@ NULL 1
2 2
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT a FROM t1 WHERE t1.a=t2.a), a FROM t2 {
"steps": [
{
@@ -171,7 +171,7 @@ SELECT (SELECT a FROM t1 WHERE t1.a=t2.a
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
# Subselect execute is traced only the first time it is executed
SET @@optimizer_trace_features="greedy_search=off,repeated_subselect=off";
@@ -181,7 +181,7 @@ NULL 1
2 2
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT a FROM t1 WHERE t1.a=t2.a), a FROM t2 {
"steps": [
{
@@ -326,7 +326,7 @@ SELECT (SELECT a FROM t1 WHERE t1.a=t2.a
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
SET @@optimizer_trace_features="default";
@@ -339,7 +339,7 @@ t1.a= (SELECT a FROM t2 LIMIT 1) ;
a
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT t1.a
FROM t1
WHERE t1.a= (SELECT b FROM t2 LIMIT 1) AND NOT
@@ -461,7 +461,7 @@ t1.a= (SELECT a FROM t2 LIMIT 1) {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SELECT 1 FROM DUAL
WHERE NOT EXISTS
@@ -470,7 +470,7 @@ WHERE NOT EXISTS
1
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT 1 FROM DUAL
WHERE NOT EXISTS
(SELECT * FROM t2 WHERE a = 50 AND b = 3) {
@@ -595,6 +595,6 @@ WHERE NOT EXISTS
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
=== modified file 'mysql-test/r/optimizer_trace_subquery_ps_prot.result'
--- a/mysql-test/r/optimizer_trace_subquery_ps_prot.result 2011-03-01 10:55:27 +0000
+++ b/mysql-test/r/optimizer_trace_subquery_ps_prot.result 2011-05-04 20:53:28 +0000
@@ -12,7 +12,7 @@ NULL 1
2 2
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT a FROM t1 WHERE t1.a=t2.a), a FROM t2 {
"steps": [
{
@@ -171,7 +171,7 @@ SELECT (SELECT a FROM t1 WHERE t1.a=t2.a
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
# Subselect execute is traced only the first time it is executed
SET @@optimizer_trace_features="greedy_search=off,repeated_subselect=off";
@@ -181,7 +181,7 @@ NULL 1
2 2
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT (SELECT a FROM t1 WHERE t1.a=t2.a), a FROM t2 {
"steps": [
{
@@ -326,7 +326,7 @@ SELECT (SELECT a FROM t1 WHERE t1.a=t2.a
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
SET @@optimizer_trace_features="default";
@@ -339,7 +339,7 @@ t1.a= (SELECT a FROM t2 LIMIT 1) ;
a
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT t1.a
FROM t1
WHERE t1.a= (SELECT b FROM t2 LIMIT 1) AND NOT
@@ -461,7 +461,7 @@ t1.a= (SELECT a FROM t2 LIMIT 1) {
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
SELECT 1 FROM DUAL
WHERE NOT EXISTS
@@ -470,7 +470,7 @@ WHERE NOT EXISTS
1
SELECT * FROM information_schema.OPTIMIZER_TRACE;
-QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE
+QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
SELECT 1 FROM DUAL
WHERE NOT EXISTS
(SELECT * FROM t2 WHERE a = 50 AND b = 3) {
@@ -595,6 +595,6 @@ WHERE NOT EXISTS
} /* join_execution */
}
] /* steps */
-} 0
+} 0 0
DROP TABLE t1,t2;
=== modified file 'mysql-test/suite/funcs_1/r/is_columns_is.result'
--- a/mysql-test/suite/funcs_1/r/is_columns_is.result 2011-03-21 17:55:41 +0000
+++ b/mysql-test/suite/funcs_1/r/is_columns_is.result 2011-05-04 20:53:28 +0000
@@ -125,6 +125,7 @@ def information_schema KEY_COLUMN_USAGE
def information_schema KEY_COLUMN_USAGE TABLE_CATALOG 4 NO varchar 512 1536 NULL NULL utf8 utf8_general_ci varchar(512) select
def information_schema KEY_COLUMN_USAGE TABLE_NAME 6 NO varchar 64 192 NULL NULL utf8 utf8_general_ci varchar(64) select
def information_schema KEY_COLUMN_USAGE TABLE_SCHEMA 5 NO varchar 64 192 NULL NULL utf8 utf8_general_ci varchar(64) select
+def information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES 4 0 NO tinyint NULL NULL 3 0 NULL NULL tinyint(1) select
def information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE 3 0 NO int NULL NULL 10 0 NULL NULL int(20) select
def information_schema OPTIMIZER_TRACE QUERY 1 NULL NO longtext 4294967295 4294967295 NULL NULL utf8 utf8_general_ci longtext select
def information_schema OPTIMIZER_TRACE TRACE 2 NULL NO longtext 4294967295 4294967295 NULL NULL utf8 utf8_general_ci longtext select
@@ -377,6 +378,7 @@ COL_CML DATA_TYPE CHARACTER_SET_NAME COL
NULL bigint NULL NULL
NULL datetime NULL NULL
NULL int NULL NULL
+NULL tinyint NULL NULL
--> CHAR(0) is allowed (see manual), and here both CHARACHTER_* values
--> are 0, which is intended behavior, and the result of 0 / 0 IS NULL
SELECT CHARACTER_OCTET_LENGTH / CHARACTER_MAXIMUM_LENGTH AS COL_CML,
@@ -519,6 +521,7 @@ NULL information_schema KEY_COLUMN_USAGE
1.0000 information_schema OPTIMIZER_TRACE QUERY longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
1.0000 information_schema OPTIMIZER_TRACE TRACE longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
NULL information_schema OPTIMIZER_TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE int NULL NULL NULL NULL int(20)
+NULL information_schema OPTIMIZER_TRACE INSUFFICIENT_PRIVILEGES tinyint NULL NULL NULL NULL tinyint(1)
3.0000 information_schema PARAMETERS SPECIFIC_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
3.0000 information_schema PARAMETERS SPECIFIC_SCHEMA varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema PARAMETERS SPECIFIC_NAME varchar 64 192 utf8 utf8_general_ci varchar(64)
=== removed file 'mysql-test/t/optimizer_trace_bugs.test'
--- a/mysql-test/t/optimizer_trace_bugs.test 2010-09-18 16:25:43 +0000
+++ b/mysql-test/t/optimizer_trace_bugs.test 1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
-# unfixed bugs. Should be deleted before push.
-
---source include/have_optimizer_trace.inc
-
-# no test here so far
-select 1;
=== modified file 'mysql-test/t/optimizer_trace_debug.test'
--- a/mysql-test/t/optimizer_trace_debug.test 2011-03-08 07:18:14 +0000
+++ b/mysql-test/t/optimizer_trace_debug.test 2011-05-04 20:53:28 +0000
@@ -5,15 +5,12 @@
--source include/have_debug.inc
--echo # We want to make sure that the common case of
---echo # a connection which has not enabled tracing, or is
---echo # running SQL commands which are excluded from
---echo # tracing, or commands which use I_S.OPTIMIZER_TRACE,
---echo # outside of any tricky stored-routine scenarios tested
---echo # in optimizer_trace2.test, are optimized, i.e. no trace is
---echo # created, even a dummy internal one invisible in I_S.
+--echo # a connection which has not enabled tracing,
+--echo # is optimized, i.e. neither Opt_trace_context_impl nor
+--echo # Opt_trace_context_stmt is created.
-# make server crash if it creates a trace, even a dummy internal one
-set debug="d,opt_trace_should_not_start";
+# make server crash if it creates Opt_trace_stmt
+set debug="d,no_new_opt_trace_stmt";
# tracable but tracing is off
select 1;
@@ -22,18 +19,15 @@ select * from information_schema.OPTIMIZ
# non-tracable
set @a=25;
-set optimizer_trace="enabled=on";
-select * from information_schema.OPTIMIZER_TRACE;
+# Force creation of Opt_trace_context_impl and Opt_trace_stmt
set debug="default";
+set optimizer_trace="enabled=on";
select 2;
-set debug="d,opt_trace_should_not_start";
select * from information_schema.OPTIMIZER_TRACE;
-set @a=25;
set optimizer_trace="enabled=off";
+set debug="d,no_new_opt_trace_stmt";
# tracable, but tracing is off again (thd->opt_trace->is_started() is false)
select 3;
# should see only trace of "select 2"
select * from information_schema.OPTIMIZER_TRACE;
-
-set optimizer_trace=default;
=== added file 'mysql-test/t/optimizer_trace_security_no_prot.test'
--- a/mysql-test/t/optimizer_trace_security_no_prot.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_trace_security_no_prot.test 2011-05-04 20:53:28 +0000
@@ -0,0 +1,8 @@
+if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL + $CURSOR_PROTOCOL
+ + $VIEW_PROTOCOL > 0`)
+{
+ --skip Need normal protocol
+}
+
+# The main testing script
+--source include/optimizer_trace_security.inc
=== added file 'mysql-test/t/optimizer_trace_security_ps_prot.test'
--- a/mysql-test/t/optimizer_trace_security_ps_prot.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/optimizer_trace_security_ps_prot.test 2011-05-04 20:53:28 +0000
@@ -0,0 +1,8 @@
+if (`SELECT $SP_PROTOCOL + $CURSOR_PROTOCOL + $VIEW_PROTOCOL > 0
+ OR $PS_PROTOCOL = 0`)
+{
+ --skip Need ps-protocol
+}
+
+# The main testing script
+--source include/optimizer_trace_security.inc
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2011-04-05 07:34:13 +0000
+++ b/sql/item_subselect.cc 2011-05-04 20:53:28 +0000
@@ -307,11 +307,10 @@ bool Item_subselect::exec()
2) REPEATED_SUBSELECT is disabled
*/
#ifdef OPTIMIZER_TRACE
- Opt_trace_context * const trace= thd->opt_trace;
- const bool repeated_trace_enabled= trace ?
- trace->feature_enabled(Opt_trace_context::REPEATED_SUBSELECT) :
- false;
- const bool disable_trace= (traced_before && !repeated_trace_enabled);
+ Opt_trace_context * const trace= &thd->opt_trace;
+ const bool disable_trace=
+ traced_before &&
+ !trace->feature_enabled(Opt_trace_context::REPEATED_SUBSELECT);
Opt_trace_disable_I_S disable_trace_wrapper(trace, disable_trace);
traced_before= true;
@@ -1144,7 +1143,7 @@ Item_in_subselect::single_value_transfor
!(select_lex->next_select()) &&
select_lex->table_list.elements)
{
- OPT_TRACE_TRANSFORM(thd->opt_trace, oto0, oto1,
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1,
select_lex->select_number,
"> ALL/ANY (SELECT)", "SELECT(MIN)");
oto1.add("chosen", true);
@@ -1193,7 +1192,7 @@ Item_in_subselect::single_value_transfor
}
else
{
- OPT_TRACE_TRANSFORM(thd->opt_trace, oto0, oto1,
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1,
select_lex->select_number,
"> ALL/ANY (SELECT)", "MIN (SELECT)");
oto1.add("chosen", true);
@@ -1300,7 +1299,7 @@ Item_in_subselect::single_value_in_to_ex
SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::single_value_in_to_exists_transformer");
- OPT_TRACE_TRANSFORM(thd->opt_trace, oto0, oto1, select_lex->select_number,
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1, select_lex->select_number,
"IN (SELECT)", "EXISTS (CORRELATED SELECT)");
oto1.add("chosen", true);
@@ -1580,7 +1579,7 @@ Item_in_subselect::row_value_in_to_exist
!select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::row_value_in_to_exists_transformer");
- OPT_TRACE_TRANSFORM(thd->opt_trace, oto0, oto1, select_lex->select_number,
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1, select_lex->select_number,
"IN (SELECT)", "EXISTS (CORRELATED SELECT)");
oto1.add("chosen", true);
@@ -1972,7 +1971,7 @@ bool Item_in_subselect::setup_engine()
subselect_single_select_engine *old_engine_derived=
static_cast<subselect_single_select_engine*>(old_engine);
- OPT_TRACE_TRANSFORM(thd->opt_trace, oto0, oto1,
+ OPT_TRACE_TRANSFORM(&thd->opt_trace, oto0, oto1,
old_engine_derived->join->select_lex->select_number,
"IN (SELECT)", "materialization");
oto1.add("chosen", true);
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2011-04-12 15:33:01 +0000
+++ b/sql/mysqld.cc 2011-05-04 20:53:28 +0000
@@ -2487,10 +2487,10 @@ the thread stack. Please read http://dev
fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id);
fprintf(stderr, "Status: %s\n", kreason);
#ifdef OPTIMIZER_TRACE
- if ((thd->opt_trace != NULL) && thd->opt_trace->is_started())
+ if (thd->opt_trace.is_started())
{
const size_t max_print_len= 4096; // print those final bytes
- const char *tail= thd->opt_trace->get_tail(max_print_len);
+ const char *tail= thd->opt_trace.get_tail(max_print_len);
fprintf(stderr, "Tail of Optimizer trace (%p): ", tail);
my_safe_print_str(tail, max_print_len);
}
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2011-04-14 11:49:41 +0000
+++ b/sql/opt_range.cc 2011-05-04 20:53:28 +0000
@@ -2082,7 +2082,7 @@ void TRP_RANGE::trace_basic_info(const P
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");
+ Opt_trace_array trace_range(¶m->thd->opt_trace, "ranges");
// TRP_RANGE should not be created if there are no range intervals
DBUG_ASSERT(key);
@@ -2149,8 +2149,8 @@ void TRP_ROR_INTERSECT::trace_basic_info
add("covering", is_covering).
add("clustered_pk_scan", cpk_scan != NULL);
- Opt_trace_context *trace_ctx= param->thd->opt_trace;
- Opt_trace_array ota(trace_ctx, "intersect_of");
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
+ Opt_trace_array ota(trace, "intersect_of");
for (st_ror_scan_info **cur_scan= first_scan;
cur_scan != last_scan;
cur_scan++)
@@ -2158,11 +2158,11 @@ void TRP_ROR_INTERSECT::trace_basic_info
const KEY &cur_key= param->table->key_info[(*cur_scan)->keynr];
const KEY_PART_INFO *key_part= cur_key.key_part;
- Opt_trace_object trace_isect_idx(trace_ctx);
+ Opt_trace_object trace_isect_idx(trace);
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");
+ Opt_trace_array trace_range(trace, "ranges");
for (const SEL_ARG *current= (*cur_scan)->sel_arg;
current;
current= current->next)
@@ -2208,13 +2208,14 @@ void TRP_ROR_UNION::trace_basic_info(con
Opt_trace_object *trace_object) const
{
#ifdef OPTIMIZER_TRACE
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
trace_object->add_alnum("type", "index_roworder_union");
- Opt_trace_array ota(param->thd->opt_trace, "union_of");
+ Opt_trace_array ota(trace, "union_of");
for (TABLE_READ_PLAN **current= first_ror;
current != last_ror;
current++)
{
- Opt_trace_object trp_info(param->thd->opt_trace);
+ Opt_trace_object trp_info(trace);
(*current)->trace_basic_info(param, &trp_info);
}
#endif
@@ -2244,13 +2245,14 @@ void TRP_INDEX_MERGE::trace_basic_info(c
Opt_trace_object *trace_object) const
{
#ifdef OPTIMIZER_TRACE
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
trace_object->add_alnum("type", "index_merge");
- Opt_trace_array ota(param->thd->opt_trace, "index_merge_of");
+ Opt_trace_array ota(trace, "index_merge_of");
for (TRP_RANGE **current= range_scans;
current != range_scans_end;
current++)
{
- Opt_trace_object trp_info(param->thd->opt_trace);
+ Opt_trace_object trp_info(trace);
(*current)->trace_basic_info(param, &trp_info);
}
#endif
@@ -2341,16 +2343,16 @@ void TRP_GROUP_MIN_MAX::trace_basic_info
add("cost", read_cost);
const KEY_PART_INFO *key_part= index_info->key_part;
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
{
- Opt_trace_array trace_keyparts(param->thd->opt_trace,
- "key_parts_used_for_access");
+ Opt_trace_array trace_keyparts(trace, "key_parts_used_for_access");
for (uint partno= 0; partno < used_key_parts; partno++)
{
const KEY_PART_INFO *cur_key_part= key_part + partno;
trace_keyparts.add_utf8(cur_key_part->field->field_name);
}
}
- Opt_trace_array trace_range(param->thd->opt_trace, "ranges");
+ Opt_trace_array trace_range(trace, "ranges");
// can have group quick without ranges
if (index_tree)
@@ -2500,7 +2502,7 @@ int SQL_SELECT::test_quick_select(THD *t
else if (read_time <= 2.0 && !force_quick_range)
DBUG_RETURN(0); /* No need for quick select */
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Opt_trace_object trace_range(trace, "range_analysis");
Opt_trace_object(trace, "table_scan").
add("records", head->file->stats.records).
@@ -4149,7 +4151,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
DBUG_ENTER("get_best_disjunct_quick");
DBUG_PRINT("info", ("Full table scan cost: %g", read_time));
- Opt_trace_context * const trace= param->thd->opt_trace;
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
Opt_trace_object trace_best_disjunct(trace);
if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root,
sizeof(TRP_RANGE*)*
@@ -4947,10 +4949,10 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
{
uint idx;
double min_cost= DBL_MAX;
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
DBUG_ENTER("get_best_ror_intersect");
- Opt_trace_object trace_ror(param->thd->opt_trace,
- "analyzing_roworder_intersect");
+ Opt_trace_object trace_ror(trace, "analyzing_roworder_intersect");
if ((tree->n_ror_scans < 2) || !param->table->file->stats.records ||
!param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
@@ -5032,11 +5034,10 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
Note: trace_isect_idx.end() is called to close this object after
this while-loop.
*/
- Opt_trace_array trace_isect_idx(param->thd->opt_trace,
- "intersecting_indices");
+ Opt_trace_array trace_isect_idx(trace, "intersecting_indices");
while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
{
- Opt_trace_object trace_idx(param->thd->opt_trace);
+ Opt_trace_object trace_idx(trace);
char *idx_name= param->table->key_info[(*cur_ror_scan)->keynr].name;
trace_idx.add_utf8("index", idx_name);
/* S= S + first(R); R= R - first(R); */
@@ -5089,7 +5090,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
covering, it doesn't make sense to add CPK scan.
*/
{ // Scope for trace object
- Opt_trace_object trace_cpk(param->thd->opt_trace, "clustered_pk");
+ Opt_trace_object trace_cpk(trace, "clustered_pk");
if (cpk_scan && !intersect->is_covering)
{
if (ror_intersect_add(intersect, cpk_scan, TRUE) &&
@@ -5192,7 +5193,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror
DBUG_ENTER("get_best_covering_ror_intersect");
// None of our tests enter this function
- Opt_trace_object (param->thd->opt_trace).
+ Opt_trace_object (¶m->thd->opt_trace).
add("get_best_covering_roworder_intersect", true).
add("untested_code", true).
add("need_tracing",true);
@@ -5349,6 +5350,7 @@ static TRP_RANGE *get_key_scans_params(P
DBUG_ENTER("get_key_scans_params");
LINT_INIT(best_mrr_flags); /* protected by key_to_read */
LINT_INIT(best_buf_size); /* protected by key_to_read */
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
/*
Note that there may be trees that have type SEL_TREE::KEY but contain no
key reads at all, e.g. tree for expression "key1 is not null" where key1
@@ -5356,7 +5358,7 @@ static TRP_RANGE *get_key_scans_params(P
*/
DBUG_EXECUTE("info", print_sel_tree(param, tree, &tree->keys_map,
"tree scans"););
- Opt_trace_array ota(param->thd->opt_trace, "range_scan_alternatives");
+ Opt_trace_array ota(trace, "range_scan_alternatives");
tree->ror_scans_map.clear_all();
tree->n_ror_scans= 0;
@@ -5376,7 +5378,7 @@ static TRP_RANGE *get_key_scans_params(P
bool read_index_only= index_read_must_be_used ? TRUE :
(bool) param->table->covering_keys.is_set(keynr);
- Opt_trace_object trace_idx(param->thd->opt_trace);
+ Opt_trace_object trace_idx(trace);
trace_idx.add_utf8("index", param->table->key_info[keynr].name);
found_records= check_quick_select(param, idx, read_index_only, *key,
@@ -5386,9 +5388,9 @@ static TRP_RANGE *get_key_scans_params(P
#ifdef OPTIMIZER_TRACE
// check_quick_select() says don't use range if it returns HA_POS_ERROR
if (found_records != HA_POS_ERROR &&
- param->thd->opt_trace && param->thd->opt_trace->is_started())
+ param->thd->opt_trace.is_started())
{
- Opt_trace_array trace_range(param->thd->opt_trace, "ranges");
+ Opt_trace_array trace_range(¶m->thd->opt_trace, "ranges");
const KEY &cur_key= param->table->key_info[keynr];
const KEY_PART_INFO *key_part= cur_key.key_part;
@@ -6605,8 +6607,8 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item
end:
if (impossible_cond_cause)
{
- Opt_trace_object wrapper (param->thd->opt_trace);
- Opt_trace_object (param->thd->opt_trace, "impossible_condition",
+ Opt_trace_object wrapper (¶m->thd->opt_trace);
+ Opt_trace_object (¶m->thd->opt_trace, "impossible_condition",
Opt_trace_context::RANGE_OPTIMIZER).
add_alnum("cause", impossible_cond_cause);
}
@@ -10147,10 +10149,11 @@ get_best_group_min_max(PARAM *param, SEL
ha_rows best_quick_prefix_records= 0;
uint best_param_idx= 0;
List_iterator<Item> select_items_it;
+ Opt_trace_context * const trace= ¶m->thd->opt_trace;
DBUG_ENTER("get_best_group_min_max");
- Opt_trace_object trace_group(thd->opt_trace, "group_index_range",
+ Opt_trace_object trace_group(trace, "group_index_range",
Opt_trace_context::RANGE_OPTIMIZER);
const char* cause= NULL;
@@ -10255,12 +10258,11 @@ get_best_group_min_max(PARAM *param, SEL
SEL_ARG *cur_index_tree= NULL;
ha_rows cur_quick_prefix_records= 0;
uint cur_param_idx= MAX_KEY;
- Opt_trace_array trace_indices(thd->opt_trace,
- "potential_group_range_indices");
+ Opt_trace_array trace_indices(trace, "potential_group_range_indices");
for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
cur_index_info++, cur_index++)
{
- Opt_trace_object trace_idx(thd->opt_trace);
+ Opt_trace_object trace_idx(trace);
trace_idx.add_utf8("index", cur_index_info->name);
KEY_PART_INFO *cur_part;
KEY_PART_INFO *end_part; /* Last part for loops. */
@@ -10547,9 +10549,9 @@ get_best_group_min_max(PARAM *param, SEL
#ifdef OPTIMIZER_TRACE
if (cur_index_tree &&
- param->thd->opt_trace && param->thd->opt_trace->is_started())
+ param->thd->opt_trace.is_started())
{
- Opt_trace_array trace_range(param->thd->opt_trace, "ranges");
+ Opt_trace_array trace_range(¶m->thd->opt_trace, "ranges");
const KEY_PART_INFO *key_part= cur_index_info->key_part;
=== modified file 'sql/opt_trace.cc'
--- a/sql/opt_trace.cc 2011-04-14 13:02:22 +0000
+++ b/sql/opt_trace.cc 2011-05-04 20:53:28 +0000
@@ -26,6 +26,56 @@
#ifdef OPTIMIZER_TRACE
+namespace {
+/**
+ A wrapper of class String, for storing query or trace.
+ Any memory allocation error in this class is reported by my_error(), see
+ OOM_HANDLING in opt_trace.h.
+*/
+class Buffer
+{
+private:
+ size_t allowed_mem_size; ///< allowed memory size for this String
+ size_t missing_bytes; ///< how many bytes could not be added
+ String string_buf;
+public:
+ Buffer() : allowed_mem_size(0), missing_bytes(0) {}
+
+ uint32 alloced_length() const { return string_buf.alloced_length(); }
+ uint32 length() const { return string_buf.length(); }
+ void prealloc(); ///< pro-actively extend buffer if soon short of space
+ char *c_ptr_safe() { return string_buf.c_ptr_safe(); }
+ const char *ptr() const { return string_buf.ptr(); }
+
+ const CHARSET_INFO *charset() const { return string_buf.charset(); }
+ void set_charset(const CHARSET_INFO *charset)
+ { string_buf.set_charset(charset); }
+
+ /**
+ Like @c String::append()
+ @param str String, in this instance's charset
+ @param length length of string
+ */
+ void append(const char *str, size_t length);
+ void append(const char *str) { return append(str, strlen(str)); }
+ /**
+ Like @c append() but escapes certain characters for string values to
+ be JSON-compliant.
+ @param str String in UTF8
+ @param length length of string
+ */
+ void append_escaped(const char *str, size_t length);
+ void append(char chr);
+
+ size_t get_allowed_mem_size() const { return allowed_mem_size; }
+ size_t get_missing_bytes() const { return missing_bytes; }
+
+ void set_allowed_mem_size(size_t a) { allowed_mem_size= a; }
+};
+
+
+} // namespace
+
/**
@class Opt_trace_stmt
@@ -38,12 +88,10 @@ class Opt_trace_stmt
{
public:
/**
- Constructor, starts a trace
+ Constructor, starts a trace for information_schema and dbug.
@param ctx_arg context
- @param support_I_S_arg should trace be in information_schema
*/
- Opt_trace_stmt(Opt_trace_context *ctx_arg,
- enum enum_support_I_S support_I_S_arg);
+ Opt_trace_stmt(Opt_trace_context *ctx_arg);
/**
Ends a trace; destruction may not be possible immediately as we may have
@@ -151,8 +199,6 @@ public:
/// @returns 'size' last bytes of the trace buffer
const char *trace_buffer_tail(size_t size);
- enum enum_support_I_S get_support_I_S() const { return support_I_S; }
-
/// @returns total memory used by this trace
size_t alloced_length() const
{ return trace_buffer.alloced_length() + query_buffer.alloced_length(); }
@@ -160,110 +206,44 @@ public:
void assert_current_struct(const Opt_trace_struct *s) const
{ DBUG_ASSERT(current_struct == s); }
-private:
+ void missing_privilege();
- bool ended; ///< Whether @c end() has been called on this instance
+ bool support_I_S() const { return I_S_disabled == 0; }
- /// Should this trace be in information_schema
- enum enum_support_I_S support_I_S;
-
- Opt_trace_context *ctx; ///< context
- Opt_trace_struct *current_struct; ///< current open structure
-
- /// Same logic as Opt_trace_context::stack_of_current_stmts.
- Dynamic_array<Opt_trace_struct *> stack_of_current_structs;
+ /// Temporarily disables I_S output for this statement.
+ void disable_I_S() { ++I_S_disabled; }
/**
- When we temporarily disable I_S (because of Opt_trace_disable_I_S, or
- because we are entering a structure belonging to a not-traced optimizer
- feature), we need to remember the pre-disabling state, to restore it
- later.
+ Restores I_S support to what it was before the previous call
+ to disable_I_S().
*/
- Dynamic_array<enum enum_support_I_S> stack_of_values_of_support_I_S;
+ void restore_I_S() { --I_S_disabled; }
- /**
- Temporarily disables I_S. This is private because only our friend
- Opt_trace_disable_I_S is trusted enough to use it.
- @retval false ok
- @retval true error (function had no effect, no disabling was done)
- */
- bool disable_I_S_for_this_and_children()
- {
- if (unlikely(stack_of_values_of_support_I_S.append(support_I_S)))
- {
- /*
- Note that append() above calls my_error() if it fails, so user is
- informed.
- */
- return true;
- }
- support_I_S= NO_FOR_THIS_AND_CHILDREN;
- return false;
- }
- /**
- Restores I_S support to what it was before the previous successful call
- to disable_I_S_for_this_and_children().
- @note we said "_successful_": indeed if we failed to append() to the
- dynamic array before, a pop() now would be wrong: it would pop a wrong
- cell, or if no cell, would dereference a NULL pointer (@sa pop_dynamic())
- and crash.
- */
- void restore_I_S()
- {
- support_I_S= stack_of_values_of_support_I_S.pop();
- }
- friend Opt_trace_disable_I_S::Opt_trace_disable_I_S(Opt_trace_context*, bool);
- friend Opt_trace_disable_I_S::~Opt_trace_disable_I_S();
+private:
+
+ bool ended; ///< Whether @c end() has been called on this instance
/**
- A wrapper of class String, for storing query or trace.
- Any memory allocation error in this class is reported by my_error(), see
- OOM_HANDLING in opt_trace.h.
+ 0 <=> this trace should be in information_schema.
+ In the life of an Opt_trace_stmt, support for I_S may be temporarily
+ disabled.
+ Once disabled, it must stay disabled until re-enabled at the same stack
+ frame. This:
+ Opt_trace_object1 // disables I_S
+ Opt_trace_object2 // re-enables I_S
+ is impossible (the top object wins).
+ So it is sufficient, to keep track of the current state, to have a counter
+ incremented each time we get a request to disable I_S.
*/
- class Buffer
- {
- private:
- size_t allowed_mem_size; ///< allowed memory size for this String
- size_t missing_bytes; ///< how many bytes could not be added
- String string_buf;
- public:
- Buffer() : allowed_mem_size(0), missing_bytes(0) {}
-
- uint32 alloced_length() const { return string_buf.alloced_length(); }
- uint32 length() const { return string_buf.length(); }
- void prealloc(); ///< pro-actively extend buffer if soon short of space
- char *c_ptr_safe()
- {
- // Alas, String::c_ptr_safe() does no realloc error checking
- return string_buf.c_ptr_safe();
- }
- const char *ptr() const { return string_buf.ptr(); }
+ int I_S_disabled;
- const CHARSET_INFO *charset() const { return string_buf.charset(); }
- void set_charset(const CHARSET_INFO *charset)
- { string_buf.set_charset(charset); }
-
- /**
- Like @c String::append()
- @param str String, in this instance's charset
- @param length length of string
- */
- void append(const char *str, size_t length);
- void append(const char *str) { return append(str, strlen(str)); }
- /**
- Like @c append() but escapes certain characters for string values to
- be JSON-compliant.
- @param str String in UTF8
- @param length length of string
- */
- void append_escaped(const char *str, size_t length);
- void append(char chr);
+ bool missing_priv; ///< whether user lacks privilege to see this trace
- size_t get_allowed_mem_size() const { return allowed_mem_size; }
- size_t get_missing_bytes() const { return missing_bytes; }
+ Opt_trace_context *ctx; ///< context
+ Opt_trace_struct *current_struct; ///< current open structure
- void set_allowed_mem_size(size_t a) { allowed_mem_size= a; }
- }; // end of class Buffer
+ /// Same logic as Opt_trace_context::stack_of_current_stmts.
+ Dynamic_array<Opt_trace_struct *> stack_of_current_structs;
Buffer trace_buffer; ///< Where the trace is accumulated
Buffer query_buffer; ///< Where the original query is put
@@ -448,9 +428,8 @@ const char *Opt_trace_struct::check_key(
// Implementation of Opt_trace_stmt class
-Opt_trace_stmt::Opt_trace_stmt(Opt_trace_context *ctx_arg,
- enum enum_support_I_S support_I_S_arg):
- ended(false), support_I_S(support_I_S_arg), ctx(ctx_arg),
+Opt_trace_stmt::Opt_trace_stmt(Opt_trace_context *ctx_arg) :
+ ended(false), I_S_disabled(0), missing_priv(false), ctx(ctx_arg),
current_struct(NULL)
{
// Trace is always in UTF8. This is the only charset which JSON accepts.
@@ -462,7 +441,7 @@ Opt_trace_stmt::Opt_trace_stmt(Opt_trace
void Opt_trace_stmt::end()
{
DBUG_ASSERT(stack_of_current_structs.elements() == 0);
- DBUG_ASSERT(stack_of_values_of_support_I_S.elements() == 0);
+ DBUG_ASSERT(I_S_disabled >= 0);
ended= true;
/*
Because allocation is done in big chunks, buffer->Ptr[str_length]
@@ -485,6 +464,8 @@ void Opt_trace_stmt::end()
DBUG_UNLOCK_FILE;
}
);
+ if (unlikely(missing_priv))
+ ctx->restore_I_S();
}
@@ -500,7 +481,7 @@ void Opt_trace_stmt::set_query(const cha
// Should be called only once per statement.
DBUG_ASSERT(query_buffer.ptr() == NULL);
query_buffer.set_charset(charset);
- if (support_I_S != YES_FOR_THIS)
+ if (!support_I_S())
{
/*
Query won't be read, don't waste resources storing it. Still we have set
@@ -527,7 +508,7 @@ bool Opt_trace_stmt::open_struct(const c
bool wants_disable_I_S,
char opening_bracket)
{
- if (support_I_S == YES_FOR_THIS)
+ if (support_I_S())
{
if (wants_disable_I_S)
{
@@ -548,9 +529,6 @@ bool Opt_trace_stmt::open_struct(const c
else
current_struct->add_alnum("...");
}
- if (unlikely(stack_of_values_of_support_I_S.append(support_I_S)))
- goto err;
- support_I_S= NO_FOR_THIS_AND_CHILDREN;
}
else
{
@@ -567,6 +545,8 @@ bool Opt_trace_stmt::open_struct(const c
trace_buffer.append(opening_bracket);
}
}
+ if (wants_disable_I_S)
+ ctx->disable_I_S_for_this_and_children();
{
DBUG_EXECUTE_IF("opt_trace_oom_in_open_struct",
DBUG_SET("+d,simulate_out_of_memory"););
@@ -579,12 +559,10 @@ bool Opt_trace_stmt::open_struct(const c
DBUG_EXECUTE_IF("opt_trace_oom_in_open_struct",
DBUG_SET("-d,simulate_out_of_memory"););
if (unlikely(rc))
- goto err;
+ return true;
}
current_struct= ots;
return false;
-err:
- return true;
}
@@ -593,7 +571,7 @@ void Opt_trace_stmt::close_struct(const
char closing_bracket)
{
current_struct= stack_of_current_structs.pop();
- if (support_I_S == YES_FOR_THIS)
+ if (support_I_S())
{
next_line();
trace_buffer.append(closing_bracket);
@@ -605,13 +583,13 @@ void Opt_trace_stmt::close_struct(const
}
}
if (has_disabled_I_S)
- support_I_S= stack_of_values_of_support_I_S.pop();
+ ctx->restore_I_S();
}
void Opt_trace_stmt::separator()
{
- DBUG_ASSERT(support_I_S == YES_FOR_THIS);
+ DBUG_ASSERT(support_I_S());
// Put a comma first, if we have already written an object at this level.
if (current_struct != NULL)
{
@@ -651,7 +629,7 @@ void Opt_trace_stmt::next_line()
void Opt_trace_stmt::add(const char *key, const char *val, size_t val_length,
bool quotes, bool escape)
{
- if (support_I_S != YES_FOR_THIS)
+ if (!support_I_S())
return;
separator();
if (key != NULL)
@@ -679,7 +657,7 @@ void Opt_trace_stmt::add(const char *key
void Opt_trace_stmt::syntax_error(const char *key)
{
DBUG_PRINT("opt", ("syntax error key: %s", key));
- DBUG_ASSERT(support_I_S == YES_FOR_THIS);
+ DBUG_ASSERT(support_I_S());
#ifndef DBUG_OFF
bool no_assert_on_syntax_error= false;
DBUG_EXECUTE_IF("opt_trace_no_assert_on_syntax_error",
@@ -705,13 +683,23 @@ void Opt_trace_stmt::syntax_error(const
void Opt_trace_stmt::fill_info(Opt_trace_info *info) const
{
- info->trace_ptr= trace_buffer.ptr();
- info->trace_length= trace_buffer.length();
- info->query_ptr= query_buffer.ptr();
- info->query_length= query_buffer.length();
- info->query_charset= query_buffer.charset();
- info->missing_bytes= trace_buffer.get_missing_bytes() +
- query_buffer.get_missing_bytes();
+ if (unlikely(info->missing_priv= missing_priv))
+ {
+ info->trace_ptr= info->query_ptr= "";
+ info->trace_length= info->query_length= 0;
+ info->query_charset= &my_charset_bin;
+ info->missing_bytes= 0;
+ }
+ else
+ {
+ info->trace_ptr= trace_buffer.ptr();
+ info->trace_length= trace_buffer.length();
+ info->query_ptr= query_buffer.ptr();
+ info->query_length= query_buffer.length();
+ info->query_charset= query_buffer.charset();
+ info->missing_bytes= trace_buffer.get_missing_bytes() +
+ query_buffer.get_missing_bytes();
+ }
}
@@ -725,9 +713,24 @@ const char *Opt_trace_stmt::trace_buffer
}
-// Implementation of class Opt_trace_stmt::Buffer
+void Opt_trace_stmt::missing_privilege()
+{
+ if (!missing_priv)
+ {
+ DBUG_PRINT("opt", ("trace denied"));
+ // This mark will make the trace appear empty in OPTIMIZER_TRACE table.
+ missing_priv= true;
+ // And all substatements will not be traced.
+ ctx->disable_I_S_for_this_and_children();
+ }
+}
+
+
+// Implementation of class Buffer
-void Opt_trace_stmt::Buffer::append_escaped(const char *str, size_t length)
+namespace {
+
+void Buffer::append_escaped(const char *str, size_t length)
{
if (alloced_length() >= allowed_mem_size)
{
@@ -811,7 +814,7 @@ void Opt_trace_stmt::Buffer::append_esca
}
-void Opt_trace_stmt::Buffer::append(const char *str, size_t length)
+void Buffer::append(const char *str, size_t length)
{
if (alloced_length() >= allowed_mem_size)
{
@@ -826,7 +829,7 @@ void Opt_trace_stmt::Buffer::append(cons
}
-void Opt_trace_stmt::Buffer::append(char chr)
+void Buffer::append(char chr)
{
if (alloced_length() >= allowed_mem_size)
{
@@ -838,8 +841,7 @@ void Opt_trace_stmt::Buffer::append(char
}
-
-void Opt_trace_stmt::Buffer::prealloc()
+void Buffer::prealloc()
{
const size_t alloced= alloced_length();
const size_t first_increment= 1024;
@@ -882,6 +884,8 @@ void Opt_trace_stmt::Buffer::prealloc()
}
}
+} // namespace
+
// Implementation of Opt_trace_context class
@@ -904,54 +908,78 @@ Opt_trace_context::default_features=
Opt_trace_context::REPEATED_SUBSELECT);
-Opt_trace_context::Opt_trace_context() :
- current_stmt_in_gen(NULL), since_offset_0(0)
-{}
-
-
Opt_trace_context::~Opt_trace_context()
{
- /* There may well be some few ended traces left: */
- purge_stmts(true);
- /* All should have moved to 'del' list: */
- DBUG_ASSERT(all_stmts_for_I_S.elements() == 0);
- /* All of 'del' list should have been deleted: */
- DBUG_ASSERT(all_stmts_to_del.elements() == 0);
+ if (unlikely(impl != NULL))
+ {
+ /* There may well be some few ended traces left: */
+ purge_stmts(true);
+ /* All should have moved to 'del' list: */
+ DBUG_ASSERT(impl->all_stmts_for_I_S.elements() == 0);
+ /* All of 'del' list should have been deleted: */
+ DBUG_ASSERT(impl->all_stmts_to_del.elements() == 0);
+ delete impl;
+ }
}
-bool Opt_trace_context::start(enum enum_support_I_S support_I_S_arg,
+bool Opt_trace_context::start(bool support_I_S_arg,
+ bool support_dbug_or_support_missing_priv,
bool end_marker_arg, bool one_line_arg,
long offset_arg, long limit_arg,
ulong max_mem_size_arg, ulonglong features_arg)
{
- /*
- Decide whether to-be-created trace should support I_S.
- Sometimes the parent rules, sometimes not. If the parent
- trace was disabled due to being "before offset" (case of a positive
- offset), we don't want the new trace to inherit and be disabled (for
- example it may be 'after offset').
- */
- enum enum_support_I_S new_stmt_support_I_S;
- bool rc;
DBUG_ENTER("Opt_trace_context::start");
+ if (I_S_disabled != 0)
+ {
+ DBUG_PRINT("opt", ("opt_trace is already disabled"));
+ support_I_S_arg= false;
+ }
+
/*
- Tracing may already be started when we come here, for example if we are
- starting execution of a sub-statement of a stored routine (CALL has
- tracing enabled too).
+ Decide on optimizations possible to realize the requested support.
+ If I_S or debug output is requested, need to create an Opt_trace_stmt.
+ Same if we should support calls to Opt_trace_context::missing_privilege(),
+ because that function requires an Opt_trace_stmt.
*/
- if (current_stmt_in_gen != NULL &&
- current_stmt_in_gen->get_support_I_S() == NO_FOR_THIS_AND_CHILDREN)
+ if (!support_I_S_arg && !support_dbug_or_support_missing_priv)
{
+ // The statement will not do tracing.
+ if (likely(impl == NULL) || impl->current_stmt_in_gen == NULL)
+ {
+ /*
+ This should be the most commonly taken branch in a release binary,
+ when the connection rarely has optimizer tracing runtime-enabled.
+ It's thus important that it's optimized: we can short-cut the creation
+ and starting of Opt_trace_stmt, unlike in the next "else" branch.
+ */
+ DBUG_RETURN(false);
+ }
/*
- Tracing is strictly disabled by the caller. Thus don't listen to any
- request from the user for enabling tracing or changing settings (offset
- etc). Doing otherwise would surely bring a problem.
+ If we come here, there is a parent statement which has a trace.
+ Imagine that 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 thus not be
+ visible.
*/
- new_stmt_support_I_S= NO_FOR_THIS_AND_CHILDREN;
}
- else
+
+ DBUG_EXECUTE_IF("no_new_opt_trace_stmt", DBUG_ASSERT(0););
+
+ if (impl == NULL)
+ impl= new Opt_trace_context_impl(); // OOM-unsafe new.
+
+ /*
+ If tracing is disabled by some caller, then don't change settings (offset
+ etc). Doing otherwise would surely bring a problem.
+ */
+ if (I_S_disabled == 0)
{
/*
Here we allow a stored routine's sub-statement to enable/disable
@@ -959,83 +987,90 @@ bool Opt_trace_context::start(enum enum_
be some 'SET OPTIMIZER_TRACE="enabled=[on|off]"' to trace only certain
sub-statements.
*/
- new_stmt_support_I_S= support_I_S_arg;
- end_marker= end_marker_arg;
- one_line= one_line_arg;
- offset= offset_arg;
- limit= limit_arg;
- max_mem_size= max_mem_size_arg;
+ impl->end_marker= end_marker_arg;
+ impl->one_line= one_line_arg;
+ impl->offset= offset_arg;
+ impl->limit= limit_arg;
+ impl->max_mem_size= max_mem_size_arg;
// MISC always on
- features= Opt_trace_context::feature_value(features_arg |
- Opt_trace_context::MISC);
+ impl->features= Opt_trace_context::feature_value(features_arg |
+ Opt_trace_context::MISC);
}
- if (new_stmt_support_I_S == YES_FOR_THIS && offset >= 0)
+ if (support_I_S_arg && impl->offset >= 0)
{
/* If outside the offset/limit window, no need to support I_S */
- if (since_offset_0 < offset)
+ if (impl->since_offset_0 < impl->offset)
{
DBUG_PRINT("opt", ("disabled: since_offset_0(%ld) < offset(%ld)",
- since_offset_0, offset));
- new_stmt_support_I_S= NO_FOR_THIS;
+ impl->since_offset_0, impl->offset));
+ support_I_S_arg= false;
}
- else if (since_offset_0 >= (offset + limit))
+ else if (impl->since_offset_0 >= (impl->offset + impl->limit))
{
DBUG_PRINT("opt", ("disabled: since_offset_0(%ld) >="
" offset(%ld) + limit(%ld)",
- since_offset_0, offset, limit));
- new_stmt_support_I_S= NO_FOR_THIS;
+ impl->since_offset_0, impl->offset, impl->limit));
+ support_I_S_arg= false;
}
- since_offset_0++;
+ impl->since_offset_0++;
}
+ {
+ /*
+ OOM-unsafe "new".
+ We don't allocate it in THD's MEM_ROOT as it must survive until a next
+ statement (SELECT) reads the trace.
+ */
+ Opt_trace_stmt *stmt= new Opt_trace_stmt(this);
- // OOM-unsafe "new".
- Opt_trace_stmt *stmt= new Opt_trace_stmt(this, new_stmt_support_I_S);
-
- DBUG_PRINT("opt",("new stmt %p support_I_S %d", stmt,
- new_stmt_support_I_S));
+ DBUG_PRINT("opt",("new stmt %p support_I_S %d", stmt, support_I_S_arg));
- if (unlikely(stack_of_current_stmts.append(current_stmt_in_gen)))
- {
- // append() above called my_error()
- goto err;
- }
+ if (unlikely(impl->stack_of_current_stmts
+ .append(impl->current_stmt_in_gen)))
+ goto err; // append() above called my_error()
- if (new_stmt_support_I_S == YES_FOR_THIS)
- rc= all_stmts_for_I_S.append(stmt);
- else
- {
/*
If sending only to DBUG, don't show to the user.
Same if tracing was temporarily disabled at higher layers with
Opt_trace_disable_I_S.
So we just link it to the 'del' list for purging when ended.
*/
- rc= all_stmts_to_del.append(stmt);
- }
+ Dynamic_array<Opt_trace_stmt *> *list;
+ if (support_I_S_arg)
+ list= &impl->all_stmts_for_I_S;
+ else
+ {
+ stmt->disable_I_S(); // no need to fill a not-shown JSON trace
+ list= &impl->all_stmts_to_del;
+ }
- if (unlikely(rc))
- goto err;
+ if (unlikely(list->append(stmt)))
+ goto err;
- current_stmt_in_gen= stmt;
+ impl->current_stmt_in_gen= stmt;
- // As we just added one trace, maybe the previous ones are unneeded now
- purge_stmts(false);
- // This purge may have freed space, compute max allowed size:
- stmt->set_allowed_mem_size(allowed_mem_size_for_current_stmt());
- DBUG_RETURN(false);
+ // As we just added one trace, maybe the previous ones are unneeded now
+ purge_stmts(false);
+ // This purge may have freed space, compute max allowed size:
+ stmt->set_allowed_mem_size(allowed_mem_size_for_current_stmt());
+ DBUG_RETURN(false);
err:
- delete stmt;
- DBUG_RETURN(true);
+ delete stmt;
+ DBUG_ASSERT(0);
+ DBUG_RETURN(true);
+ }
}
void Opt_trace_context::end()
{
- if (current_stmt_in_gen != NULL)
+ DBUG_ASSERT(I_S_disabled >= 0);
+ if (likely(impl == NULL))
+ return;
+ if (impl->current_stmt_in_gen != NULL)
{
- current_stmt_in_gen->end();
- Opt_trace_stmt * const parent= stack_of_current_stmts.pop();
- current_stmt_in_gen= parent;
+ impl->current_stmt_in_gen->end();
+ Opt_trace_stmt * const parent= impl->stack_of_current_stmts.pop();
+ impl->current_stmt_in_gen= parent;
if (parent != NULL)
{
/*
@@ -1044,42 +1079,42 @@ void Opt_trace_context::end()
*/
parent->set_allowed_mem_size(allowed_mem_size_for_current_stmt());
}
+ /*
+ Purge again. Indeed when we are here, compared to the previous start()
+ we have one more ended trace, so can potentially free more. Consider
+ offset=-1 and:
+ top_stmt, started
+ sub_stmt, starts: can't free top_stmt as it is not ended yet
+ sub_stmt, ends: won't free sub_stmt (as user will want to see it),
+ can't free top_stmt as not ended yet
+ top_stmt, continued
+ top_stmt, ends: free top_stmt as it's not last and is ended, keep only
+ sub_stmt.
+ Still the purge is done in ::start() too, as an optimization, for this
+ case:
+ sub_stmt, started
+ sub_stmt, ended
+ sub_stmt, starts: can free above sub_stmt, will save memory compared
+ to free-ing it only when the new sub_stmt ends.
+ */
+ purge_stmts(false);
}
else
- DBUG_ASSERT(stack_of_current_stmts.elements() == 0);
- /*
- Purge again. Indeed when we are here, compared to the previous start() we
- have one more ended trace, so can potentially free more. Consider
- offset=-1 and:
- top_stmt, started
- sub_stmt, starts: can't free top_stmt as it is not ended yet
- sub_stmt, ends: won't free sub_stmt (as user will want to see it),
- can't free top_stmt as not ended yet
- top_stmt, continued
- top_stmt, ends: free top_stmt as it's not last and is ended, keep only
- sub_stmt.
- Still the purge is done in ::start() too, as an optimization, for this
- case:
- sub_stmt, started
- sub_stmt, ended
- sub_stmt, starts: can free above sub_stmt, will save memory compared to
- free-ing it only when the new sub_stmt ends.
- */
- purge_stmts(false);
+ DBUG_ASSERT(impl->stack_of_current_stmts.elements() == 0);
}
bool Opt_trace_context::support_I_S() const
{
- return current_stmt_in_gen &&
- (current_stmt_in_gen->get_support_I_S() == YES_FOR_THIS);
+ return (impl != NULL) && (impl->current_stmt_in_gen != NULL) &&
+ impl->current_stmt_in_gen->support_I_S();
}
void Opt_trace_context::purge_stmts(bool purge_all)
{
DBUG_ENTER("Opt_trace_context::purge_stmts");
- if (!purge_all && offset >= 0)
+ if (!purge_all && impl->offset >= 0)
{
/* This case is managed in @c Opt_trace_context::start() */
DBUG_VOID_RETURN;
@@ -1093,9 +1128,10 @@ void Opt_trace_context::purge_stmts(bool
incremented to 1, which is past the array's end, so break out of the loop:
cell 0 (old cell 1) was not deleted, wrong).
*/
- for (idx= (all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
+ for (idx= (impl->all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
{
- if (!purge_all && ((all_stmts_for_I_S.elements() + offset) <= idx))
+ if (!purge_all &&
+ ((impl->all_stmts_for_I_S.elements() + impl->offset) <= idx))
{
/* OFFSET mandates that this trace should be kept; move to previous */
}
@@ -1107,8 +1143,9 @@ void Opt_trace_context::purge_stmts(bool
*/
DBUG_EXECUTE_IF("opt_trace_oom_in_purge",
DBUG_SET("+d,simulate_out_of_memory"););
- if (likely(!all_stmts_to_del.append(all_stmts_for_I_S.at(idx))))
- all_stmts_for_I_S.del(idx);
+ if (likely(!impl->all_stmts_to_del
+ .append(impl->all_stmts_for_I_S.at(idx))))
+ impl->all_stmts_for_I_S.del(idx);
else
{
/*
@@ -1122,9 +1159,9 @@ void Opt_trace_context::purge_stmts(bool
}
}
/* Examine list of "to be freed" traces and free what can be */
- for (idx= (all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
+ for (idx= (impl->all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
{
- Opt_trace_stmt *stmt= all_stmts_to_del.at(idx);
+ Opt_trace_stmt *stmt= impl->all_stmts_to_del.at(idx);
#ifndef DBUG_OFF
bool skip_del= false;
DBUG_EXECUTE_IF("opt_trace_oom_in_purge", skip_del= true;);
@@ -1159,7 +1196,7 @@ void Opt_trace_context::purge_stmts(bool
}
else
{
- all_stmts_to_del.del(idx);
+ impl->all_stmts_to_del.del(idx);
delete stmt;
}
}
@@ -1169,46 +1206,82 @@ void Opt_trace_context::purge_stmts(bool
size_t Opt_trace_context::allowed_mem_size_for_current_stmt() const
{
- DBUG_ENTER("Opt_trace_context::allowed_mem_size");
size_t mem_size= 0;
int idx;
- for (idx= (all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
+ for (idx= (impl->all_stmts_for_I_S.elements() - 1) ; idx >= 0 ; idx--)
{
- const Opt_trace_stmt *stmt= all_stmts_for_I_S.at(idx);
+ const Opt_trace_stmt *stmt= impl->all_stmts_for_I_S.at(idx);
mem_size+= stmt->alloced_length();
}
// Even to-be-deleted traces use memory, so consider them in sum
- for (idx= (all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
+ for (idx= (impl->all_stmts_to_del.elements() - 1) ; idx >= 0 ; idx--)
{
- const Opt_trace_stmt *stmt= all_stmts_to_del.at(idx);
+ const Opt_trace_stmt *stmt= impl->all_stmts_to_del.at(idx);
mem_size+= stmt->alloced_length();
}
/* The current statement is in exactly one of the two lists above */
- mem_size-= current_stmt_in_gen->alloced_length();
- size_t rc= (mem_size <= max_mem_size) ? (max_mem_size - mem_size) : 0;
+ mem_size-= impl->current_stmt_in_gen->alloced_length();
+ size_t rc= (mem_size <= impl->max_mem_size) ?
+ (impl->max_mem_size - mem_size) : 0;
DBUG_PRINT("opt", ("rc %llu max_mem_size %llu",
- (ulonglong)rc, (ulonglong)max_mem_size));
- DBUG_RETURN(rc);
+ (ulonglong)rc, (ulonglong)impl->max_mem_size));
+ return rc;
}
void Opt_trace_context::set_query(const char *query, size_t length,
const CHARSET_INFO *charset)
{
- current_stmt_in_gen->set_query(query, length, charset);
+ impl->current_stmt_in_gen->set_query(query, length, charset);
}
const char *Opt_trace_context::get_tail(size_t size)
{
- return current_stmt_in_gen->trace_buffer_tail(size);
+ return (impl == NULL) ? "" :
+ impl->current_stmt_in_gen->trace_buffer_tail(size);
}
void Opt_trace_context::reset()
{
+ if (impl == NULL)
+ return;
purge_stmts(true);
- since_offset_0= 0;
+ impl->since_offset_0= 0;
+}
+
+
+void Opt_trace_context::
+Opt_trace_context_impl::disable_I_S_for_this_and_children()
+{
+ if (current_stmt_in_gen != NULL)
+ current_stmt_in_gen->disable_I_S();
+}
+
+
+void Opt_trace_context::Opt_trace_context_impl::restore_I_S()
+{
+ if (current_stmt_in_gen != NULL)
+ current_stmt_in_gen->restore_I_S();
+}
+
+
+void Opt_trace_context::missing_privilege()
+{
+ /*
+ By storing the 'missing_priv' mark in Opt_trace_stmt instead of in
+ Opt_trace_context we get automatic re-enabling of I_S when the stmt ends,
+ Opt_trace_stmt::missing_priv being the "memory" of where I_S has been
+ disabled.
+ Storing in Opt_trace_context would require an external memory (probably a
+ RAII object), which would not be possible in
+ TABLE_LIST::prepare_security(), where I_S must be disabled even after the
+ end of that function - so RAII would not work.
+
+ Which is why this function needs an existing current_stmt_in_gen.
+ */
+ impl->current_stmt_in_gen->missing_privilege();
}
@@ -1216,19 +1289,20 @@ const Opt_trace_stmt
*Opt_trace_context::get_next_stmt_for_I_S(long *got_so_far) const
{
const Opt_trace_stmt *p;
- if (*got_so_far >= limit)
- p= NULL;
- else if (*got_so_far >= all_stmts_for_I_S.elements())
+ if ((impl == NULL) ||
+ (*got_so_far >= impl->limit) ||
+ (*got_so_far >= impl->all_stmts_for_I_S.elements()))
p= NULL;
else
{
- p= all_stmts_for_I_S.at(*got_so_far);
+ p= impl->all_stmts_for_I_S.at(*got_so_far);
DBUG_ASSERT(p != NULL);
(*got_so_far)++;
}
return p;
}
+
// Implementation of class Opt_trace_iterator
Opt_trace_iterator::Opt_trace_iterator(Opt_trace_context *ctx_arg) :
@@ -1257,23 +1331,16 @@ Opt_trace_disable_I_S::Opt_trace_disable
{
if (disable)
{
- if (ctx_arg != NULL)
- {
- stmt= ctx_arg->get_current_stmt_in_gen();
- if (stmt != NULL)
- if (unlikely(stmt->disable_I_S_for_this_and_children()))
- disable= false; // failed to disable: be a dummy object
- }
- else
- stmt= NULL;
+ ctx= ctx_arg;
+ ctx->disable_I_S_for_this_and_children();
}
}
Opt_trace_disable_I_S::~Opt_trace_disable_I_S()
{
- if (disable && (stmt != NULL))
- stmt->restore_I_S();
+ if (disable)
+ ctx->restore_I_S();
}
#endif // OPTIMIZER_TRACE
=== modified file 'sql/opt_trace.h'
--- a/sql/opt_trace.h 2011-04-14 13:02:22 +0000
+++ b/sql/opt_trace.h 2011-05-04 20:53:28 +0000
@@ -25,6 +25,7 @@
struct st_schema_table;
struct TABLE_LIST;
struct TABLE;
+class sp_instr;
/**
@file
@@ -335,26 +336,14 @@ struct TABLE;
As we don't support exceptions, we need new(nothrow) in order to be able to
handle OOM.
But "nothrow" is in the standard C++ library, which we don't link with.
- So we have two calls to "new" (one to create Opt_trace_context, one to
+ So we have two calls to "new" (one to create Opt_trace_context_impl, one to
create Opt_trace_stmt), which may crash. When we have nothrow we should
- change them new(nothrow).
+ change them to new(nothrow).
*/
class Opt_trace_struct;
class Opt_trace_stmt; // implementation detail local to opt_trace.cc
-/**
- The different ways a trace output can be sent to
- INFORMATION_SCHEMA.OPTIMIZER_TRACE.
- Note that a trace may also go to DBUG, independently of the values below.
-*/
-enum enum_support_I_S
-{
- YES_FOR_THIS= 0, ///< sent to I_S
- NO_FOR_THIS= 1, ///< not sent, undefined for children
- NO_FOR_THIS_AND_CHILDREN= 2 ///< not sent, and children not sent
-};
-
/**
@class Opt_trace_context
@@ -405,12 +394,18 @@ enum enum_support_I_S
class Opt_trace_context
{
public:
- Opt_trace_context();
+
+ Opt_trace_context() : impl(NULL), I_S_disabled(0) {}
~Opt_trace_context();
/**
Starts a new trace.
- @param support_I_S Should trace be in information_schema
+ @param support_I_S Whether this statement should have its trace in
+ information_schema
+ @param support_dbug_or_support_missing_priv 'true' if this statement
+ should have its trace in the dbug log (--debug),
+ or if missing_privilege() may be called on this
+ trace
@param end_marker For a key/(object|array) pair, should the key be
repeated in a comment when the object|array
closes? like
@@ -437,15 +432,25 @@ public:
destructor is permitted on it; any other
member function has undefined effects.
*/
- bool start(enum enum_support_I_S support_I_S,
+ bool start(bool support_I_S,
+ bool support_dbug_or_support_t_missing_priv,
bool end_marker, bool one_line,
long offset, long limit, ulong max_mem_size,
ulonglong features);
- /// Ends the current (=open, unfinished, being-generated) trace.
+
+ /**
+ Ends the current (=open, unfinished, being-generated) trace.
+
+ If @c missing_privilege() has been called between start() and end(),
+ end() restores I_S support to what it was before the call to
+ @c missing_privilege(). This is the key to ensure that missing_privilege()
+ does not disable I_S support for the rest of the connection's life!
+ */
void end();
/// Returns whether there is a current trace
- bool is_started() const { return current_stmt_in_gen != NULL; }
+ bool is_started() const
+ { return unlikely(impl != NULL) && impl->current_stmt_in_gen != NULL; }
/**
@returns whether the current trace writes to I_S.
@@ -480,9 +485,9 @@ public:
void reset();
/// @sa parameters of Opt_trace_context::start()
- bool get_end_marker() const { return end_marker; }
+ bool get_end_marker() const { return impl->end_marker; }
/// @sa parameters of Opt_trace_context::start()
- bool get_one_line() const { return one_line; }
+ bool get_one_line() const { return impl->one_line; }
/**
Names of flags for @@@@optimizer_trace variable of @c sys_vars.cc :
@@ -519,7 +524,7 @@ public:
GREEDY_SEARCH= 1 << 0,
RANGE_OPTIMIZER= 1 << 1,
DYNAMIC_RANGE= 1 << 2,
- REPEATED_SUBSELECT= 1 << 3, ///@todo join cache, semijoin...
+ REPEATED_SUBSELECT= 1 << 3,
/*
If you add here, update feature_value of empty implementation
and default_features!
@@ -532,6 +537,16 @@ public:
*/
MISC= 1 << 7
};
+
+ /**
+ User lacks privileges to see the current trace. Make the trace appear
+ empty in Opt_trace_info, and disable I_S for all its upcoming children.
+
+ Once a call to this function has been made, subsequent calls to it before
+ @c end() have no effects.
+ */
+ void missing_privilege();
+
static const feature_value default_features;
/**
@@ -539,14 +554,15 @@ public:
@param f feature
*/
bool feature_enabled (feature_value f) const
- { return features & f; }
+ { return unlikely(impl != NULL) && (impl->features & f); }
/**
Opt_trace_struct is passed Opt_trace_context*, and needs to know
to which statement's trace to attach, so Opt_trace_context must provide
this information.
*/
- Opt_trace_stmt *get_current_stmt_in_gen() { return current_stmt_in_gen; }
+ Opt_trace_stmt *get_current_stmt_in_gen()
+ { return impl->current_stmt_in_gen; }
/**
@returns the next statement to show in I_S.
@@ -556,77 +572,126 @@ public:
*/
const Opt_trace_stmt *get_next_stmt_for_I_S(long *got_so_far) const;
+ /// Temporarily disables I_S for this trace and its children.
+ void disable_I_S_for_this_and_children()
+ {
+ ++I_S_disabled;
+ if (unlikely(impl != NULL))
+ impl->disable_I_S_for_this_and_children();
+ }
+
+ /**
+ Restores I_S support to what it was before the previous call to
+ disable_I_S_for_this_and_children().
+ */
+ void restore_I_S()
+ {
+ --I_S_disabled;
+ DBUG_ASSERT(I_S_disabled >= 0);
+ if (unlikely(impl != NULL))
+ impl->restore_I_S();
+ }
+
private:
/**
- Trace which is currently being generated, where structures are being
- added. "in_gen" stands for "in generation", being-generated.
+ To have the smallest impact on THD's size, most of the implementation is
+ moved to a separate class Opt_trace_context_impl which is instantiated on
+ the heap when really needed. So if a connection never sets
+ @@@@optimizer_trace to "enabled=on" and does not use --debug, this heap
+ allocation never happens.
+ This class is declared here so that frequently called functions like
+ Opt_trace_context::is_started() can be inlined.
+ */
+ class Opt_trace_context_impl
+ {
+ public:
+ Opt_trace_context_impl() : current_stmt_in_gen(NULL),
+ features(feature_value(0)), offset(0), limit(0), since_offset_0(0)
+ {}
- In simple cases it is equal to the last element of array
- all_stmts_for_I_S. But it can be prior to it, for example when calling a
- stored routine:
-@verbatim
- CALL statement starts executing
- create trace of CALL (call it "trace #1")
- add structure to trace #1
- add structure to trace #1
- First sub-statement executing
- create trace of sub-statement (call it "trace #2")
- add structure to trace #2
- add structure to trace #2
- First sub-statement ends
- add structure to trace #1
-@endverbatim
- In the beginning, the CALL statement's trace is the newest and current;
- when the first sub-statement is executing, that sub-statement's trace is
- the newest and current; when the first sub-statement ends, it is still
- the newest but it's not the current anymore: the current is then again
- the CALL's one, where structures will be added, until a second
- sub-statement is executed.
- Another case is when the current statement sends only to DBUG:
- all_stmts_for_I_S lists only traces shown in OPTIMIZER_TRACE.
- */
- Opt_trace_stmt *current_stmt_in_gen;
-
- /**
- To keep track of what is the current statement, as execution goes into a
- sub-statement, and back to the upper statement, we have a stack of
- successive values of current_stmt_in_gen:
- when in a statement we enter a substatement (a new trace), we push the
- statement's trace on the stack and change current_stmt_in_gen to the
- substatement's trace; when leaving the substatement we pop from the stack
- and set current_stmt_in_gen to the popped value.
- */
- Dynamic_array<Opt_trace_stmt *> stack_of_current_stmts;
-
- /**
- List of remembered traces for putting into the OPTIMIZER_TRACE
- table. Element 0 is the one created first, will be first row of
- OPTIMIZER_TRACE table. The array structure fullfills those needs:
- - to output traces "oldest first" in OPTIMIZER_TRACE
- - to preserve traces "newest first" when @@@@optimizer_trace_offset<0
- - to delete a trace in the middle of the list when it is permanently out
+ void disable_I_S_for_this_and_children();
+ void restore_I_S();
+
+ /**
+ Trace which is currently being generated, where structures are being
+ added. "in_gen" stands for "in generation", being-generated.
+
+ In simple cases it is equal to the last element of array
+ all_stmts_for_I_S. But it can be prior to it, for example when calling a
+ stored routine:
+@verbatim
+ CALL statement starts executing
+ create trace of CALL (call it "trace #1")
+ add structure to trace #1
+ add structure to trace #1
+ First sub-statement executing
+ create trace of sub-statement (call it "trace #2")
+ add structure to trace #2
+ add structure to trace #2
+ First sub-statement ends
+ add structure to trace #1
+@endverbatim
+ In the beginning, the CALL statement's trace is the newest and current;
+ when the first sub-statement is executing, that sub-statement's trace
+ is the newest and current; when the first sub-statement ends, it is
+ still the newest but it's not the current anymore: the current is then
+ again the CALL's one, where structures will be added, until a second
+ sub-statement is executed.
+ Another case is when the current statement sends only to DBUG:
+ all_stmts_for_I_S lists only traces shown in OPTIMIZER_TRACE.
+ */
+ Opt_trace_stmt *current_stmt_in_gen;
+
+ /**
+ To keep track of what is the current statement, as execution goes into a
+ sub-statement, and back to the upper statement, we have a stack of
+ successive values of current_stmt_in_gen:
+ when in a statement we enter a substatement (a new trace), we push the
+ statement's trace on the stack and change current_stmt_in_gen to the
+ substatement's trace; when leaving the substatement we pop from the stack
+ and set current_stmt_in_gen to the popped value.
+ */
+ Dynamic_array<Opt_trace_stmt *> stack_of_current_stmts;
+
+ /**
+ List of remembered traces for putting into the OPTIMIZER_TRACE
+ table. Element 0 is the one created first, will be first row of
+ OPTIMIZER_TRACE table. The array structure fullfills those needs:
+ - to output traces "oldest first" in OPTIMIZER_TRACE
+ - to preserve traces "newest first" when @@@@optimizer_trace_offset<0
+ - to delete a trace in the middle of the list when it is permanently out
of the offset/limit showable window.
- */
- Dynamic_array<Opt_trace_stmt *> all_stmts_for_I_S;
- /**
- List of traces which are unneeded because of OFFSET/LIMIT, and scheduled
- for deletion from memory.
- */
- Dynamic_array<Opt_trace_stmt *> all_stmts_to_del;
+ */
+ Dynamic_array<Opt_trace_stmt *> all_stmts_for_I_S;
+ /**
+ List of traces which are unneeded because of OFFSET/LIMIT, and scheduled
+ for deletion from memory.
+ */
+ Dynamic_array<Opt_trace_stmt *> all_stmts_to_del;
- bool end_marker; ///< copy of parameter of Opt_trace_context::start
- bool one_line;
- feature_value features;
- long offset;
- long limit;
- size_t max_mem_size;
+ bool end_marker; ///< copy of parameter of Opt_trace_context::start
+ bool one_line;
+ feature_value features;
+ long offset;
+ long limit;
+ size_t max_mem_size;
+
+ /**
+ Number of statements traced so far since "offset 0", for comparison with
+ OFFSET and LIMIT, when OFFSET >= 0.
+ */
+ long since_offset_0;
+ };
+
+ Opt_trace_context_impl *impl;
/**
- Number of statements traced so far since "offset 0", for comparison with
- OFFSET and LIMIT, when OFFSET >= 0.
+ <>0 <=> any to-be-created statement's trace should not be in
+ information_schema. This applies to next statements, their substatements,
+ etc.
*/
- long since_offset_0;
+ int I_S_disabled;
/**
Find and delete unneeded traces.
@@ -653,7 +718,6 @@ private:
Opt_trace_context(const Opt_trace_context&);
/// Not defined assignment operator, to disallow assignment.
Opt_trace_context& operator=(const Opt_trace_context&);
-
};
@@ -683,6 +747,7 @@ struct Opt_trace_info
because of @@@@optimizer-trace-max-mem-size).
*/
size_t missing_bytes;
+ bool missing_priv; ///< whether user lacks privilege to see this trace
};
@@ -754,7 +819,7 @@ protected:
started(false)
{
// A first inlined test
- if (unlikely(ctx_arg != NULL) && ctx_arg->is_started())
+ if (unlikely(ctx_arg->is_started()))
{
// Tracing enabled: must fully initialize the structure.
do_construct(ctx_arg, requires_key_arg, key, feature);
@@ -1184,7 +1249,7 @@ public:
private:
bool disable; ///< whether this instance really does disabling.
- Opt_trace_stmt *stmt; ///< statement where disabling happens
+ Opt_trace_context *ctx;
Opt_trace_disable_I_S(const Opt_trace_disable_I_S&); // not defined
Opt_trace_disable_I_S& operator=(const Opt_trace_disable_I_S&);//not defined
};
@@ -1198,49 +1263,58 @@ private:
//@{
/**
- 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.
+ Instantiate this class to start tracing a THD's actions (generally at a
+ statement's start), and to set the "original" query (not transformed, as
+ sent by client) for the new trace. Destructor will end the trace.
+
+ If in a routine's instruction, there is no "query". To be helpful to the
+ user, we craft a query using the instruction's print(). We don't leave this
+ to the caller, because it would be inefficient if tracing is off.
+
+ @param thd the THD
+ @param tbl list of tables read/written by the statement.
@param sql_command SQL command being prepared or executed
- @returns 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
- (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,
- enum enum_sql_command sql_command);
+ @param query query
+ @param length query's length
+ @param instr routine's instruction, if applicable; if so, 'query'
+ and 'query_length' above are ignored
+ @param charset charset which was used to encode this query
-/**
- Stop tracing a THD's actions (generally at statement's end).
- @param thd the THD
- @param started whether this frame did tracing
+ @note Each sub-statement is responsible for ending the trace which it
+ has started; this class achieves this by keeping some memory inside.
*/
-void opt_trace_end(THD *thd, bool started);
+class Opt_trace_start
+{
+public:
+ Opt_trace_start(THD *thd_arg, TABLE_LIST *tbl,
+ enum enum_sql_command sql_command,
+ const char *query, size_t query_length,
+ sp_instr *instr,
+ const CHARSET_INFO *query_charset);
+ ~Opt_trace_start();
+private:
+ Opt_trace_context * const ctx;
+ bool error; ///< whether trace start() had an error
+};
+
class st_select_lex;
/**
Prints SELECT query to optimizer trace. It is not the original query (@see
- opt_trace_set_query()) but a printout of the parse tree (Item-s).
+ Opt_trace_context::set_query()) but a printout of the parse tree (Item-s).
@param thd the THD
@param select_lex query's parse tree
*/
void opt_trace_print_expanded_query(THD *thd,
st_select_lex *select_lex);
-/**
- Set the "original" query (not transformed, as sent by client) for the
- current trace.
- @param trace trace context
- @param query query
- @param length query's length
- @param charset charset which was used to encode this query
-*/
-void opt_trace_set_query(Opt_trace_context *trace, const char *query,
- size_t query_length,
- const CHARSET_INFO *query_charset);
+void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view,
+ TABLE_LIST *underlying_tables);
+
+class sp_head;
+void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp);
+
+void opt_trace_disable_if_no_security_context_access(THD *thd);
/**
Fills information_schema.OPTIMIZER_TRACE with rows (one per trace)
@@ -1267,7 +1341,7 @@ int make_optimizer_trace_table_for_show(
class Opt_trace_context
{
public:
- /// We need this enum even if tracing is disabled
+ /// We need those enums even if tracing is disabled
enum feature_value {
GREEDY_SEARCH= 1 << 0,
RANGE_OPTIMIZER= 1 << 1,
@@ -1275,6 +1349,12 @@ public:
REPEATED_SUBSELECT= 1 << 3,
MISC= 1 << 7
};
+ enum {
+ FLAG_DEFAULT= 0,
+ FLAG_ENABLED= 1 << 0,
+ FLAG_END_MARKER= 1 << 1,
+ FLAG_ONE_LINE= 1 << 2
+ };
};
/** Empty implementation used when optimizer trace is not compiled in */
@@ -1344,10 +1424,20 @@ public:
Opt_trace_disable_I_S(Opt_trace_context *ctx_arg, bool disable_arg) {}
};
-#define opt_trace_start(thd, tbl, sql_command) (false)
-#define opt_trace_end(thd, started) do {} while (0)
+class Opt_trace_start
+{
+public:
+ Opt_trace_start(THD *thd, const TABLE_LIST *tbl,
+ enum enum_sql_command sql_command,
+ const char *query, size_t query_length,
+ sp_instr *instr,
+ const CHARSET_INFO *query_charset) {}
+};
+
#define opt_trace_print_expanded_query(thd, select_lex) do {} while (0)
-#define opt_trace_set_query(trace,q,ql,cs) do {} while (0)
+#define opt_trace_disable_if_no_view_access(thd, view, underlying_tables) do {} while (0)
+#define opt_trace_disable_if_no_stored_proc_func_access(thd, sp) do {} while (0)
+#define opt_trace_disable_if_no_security_context_access(thd) do {} while (0)
#endif /* OPTIMIZER_TRACE */
=== modified file 'sql/opt_trace2server.cc'
--- a/sql/opt_trace2server.cc 2011-04-13 15:36:01 +0000
+++ b/sql/opt_trace2server.cc 2011-05-04 20:53:28 +0000
@@ -20,12 +20,13 @@
are dedicated "to the server" (hence the file's name).
In order to create a unit test of the optimizer trace without defining
Item_field (and all its parent classes), st_select_lex..., these helpers
- are defined in opt_trace.cc.
+ are defined in opt_trace2server.cc.
*/
#include "opt_trace.h"
#include "sql_show.h" // schema_table_stored_record()
#include "sql_parse.h" // sql_command_flags
+#include "sp_head.h" // for sp_head
#ifdef OPTIMIZER_TRACE
@@ -84,130 +85,121 @@ inline bool sql_command_can_be_traced(en
return (sql_command_flags[sql_command] & CF_OPTIMIZER_TRACE);
}
+
+void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl);
+
} // namespace
-bool opt_trace_start(THD *thd, const TABLE_LIST *tbl,
- enum enum_sql_command sql_command)
+
+Opt_trace_start::Opt_trace_start(THD *thd, TABLE_LIST *tbl,
+ enum enum_sql_command sql_command,
+ const char *query, size_t query_length,
+ sp_instr *instr,
+ const CHARSET_INFO *query_charset)
+ : ctx(&thd->opt_trace)
{
DBUG_ENTER("opt_trace_start");
/*
- We need an optimizer trace:
- * if the user asked for it or
- * 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:
- * 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).
+ By default, we need an optimizer trace:
+ - if the user asked for it or
+ - if we are using --debug (because the trace serves as a relay for it, for
+ optimizer debug printouts).
*/
const ulonglong var= thd->variables.optimizer_trace;
- enum enum_support_I_S support_I_S= (var & Opt_trace_context::FLAG_ENABLED) ?
- YES_FOR_THIS : NO_FOR_THIS;
- bool need_it_for_dbug= false;
- bool allocated_here= false;
+ bool support_I_S= false, support_dbug_or_support_missing_priv= false;
/* This will be triggered if --debug or --debug=d:opt_trace is used */
- DBUG_EXECUTE("opt", need_it_for_dbug= true;);
+ DBUG_EXECUTE("opt", support_dbug_or_support_missing_priv= true;);
+
// First step, decide on what type of I_S support we want
- if (!sql_command_can_be_traced(sql_command))
+ if (unlikely(var & Opt_trace_context::FLAG_ENABLED))
{
- /*
- We also constraint its substatements to do no tracing. This is an extra
- safety, to prevent against tracing happening in unexpected scenarios, in
- commands which we normally think do no tracing. Assume that in the
- future, ALTER TABLE would be able to call a stored function, like this:
- ALTER TABLE t MODIFY COLUMN c DEFAULT stored_func(d)
- ('d' being another column; to say that by default 'c' should
- calculated from 'd'). This introduces a new code path, which may lead to
- some incorrect JSON syntax in the trace.
-
- With the constraint in place, the SELECT would not be traced.
- This constraint forces us to enable trace for CALL because otherwise,
- execution of a stored procedure would not be traced. Same for SQL PREPARE
- and SQL EXECUTE.
- */
- support_I_S= NO_FOR_THIS_AND_CHILDREN;
- }
- else if (unlikely(support_I_S == YES_FOR_THIS &&
- list_has_optimizer_trace_table(tbl)))
- {
- /*
- Note that list_has_optimizer_trace_table() is an expensive function
- (scanning the list of all used tables, doing checks on their names) but
- we call it only if @@optimizer_trace has enabled=on.
- */
- support_I_S= NO_FOR_THIS;
- }
- /*
- Second step, decide on optimizations possible to realize this I_S support.
- DBUG support requires tracing, then we have no choice.
- */
- if (support_I_S != YES_FOR_THIS && !need_it_for_dbug)
- {
- // The statement will not do tracing.
- if (thd->opt_trace == NULL || !thd->opt_trace->is_started())
+ if (sql_command_can_be_traced(sql_command) && // (1)
+ !list_has_optimizer_trace_table(tbl) && // (2)
+ !thd->system_thread) // (3)
{
/*
- This should be the most commonly taken branch in a release binary,
- when the connection rarely has optimizer tracing runtime-enabled.
- It's thus important that it's optimized: we can short-cut the creation
- and starting of Opt_trace_context, unlike in the next "else" branch.
+ (1) This command is interesting Optimizer-wise.
+
+ (2) If a SELECT of I_S.OPTIMIZER_TRACE were traced, it would overwrite
+ the interesting trace of the previous statement. Note that
+ list_has_optimizer_trace_table() is an expensive function (scanning the
+ list of all used tables, doing checks on their names) but we call it
+ only if @@optimizer_trace has enabled=on.
+
+ (3) Usage of the trace in a system thread would be
+ impractical. Additionally:
+ - threads of the Events Scheduler have an unusual security context
+ (thd->main_security_ctx.priv_user==NULL, see comment in
+ Security_context::change_security_context()), so we can do no security
+ checks on them, so cannot safely enable tracing.
+ - statement-based replication of
+ "INSERT INTO real_table SELECT * FROM I_S.OPTIMIZER_TRACE" is
+ anyway impossible as @@optimizer_trace* are not replicated, and trace
+ would be different between master and slave unless data and engines and
+ version of the optimizer are strictly identical.
+ - row-based replication of the INSERT SELECT above is still allowed, it
+ does not require enabling optimizer trace on the slave.
*/
- DBUG_RETURN(false);
+ support_I_S= true;
}
else
{
/*
- If we come here, there is a parent statement which has a trace.
- Imagine that 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 thus not be
- visible.
+ - statement will not be traced in I_S,
+ - if it uses a subquery, this subquery will not be traced,
+ - if it uses a stored routine, this routine's substatements may be
+ traced.
*/
}
+ /*
+ We will do security checks. This is true even in the exceptions
+ (1)...(3) above. Otherwise, in:
+ SET OPTIMIZER_TRACE="ENABLED=ON";
+ SELECT stored_func() FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+ (exception 2), we would not check for privilege to do SHOW CREATE on
+ stored_func, then we would enter a substatement, which would be traced,
+ and would expose the function's body.
+ So we will do security checks. So need to inform the trace system that
+ it should be ready for a possible call to missing_privilege() later:
+ */
+ support_dbug_or_support_missing_priv= true;
}
- DBUG_EXECUTE_IF("opt_trace_should_not_start", DBUG_ASSERT(0););
- /*
- 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)
- {
- thd->opt_trace= new Opt_trace_context; // OOM-unsafe "new".
- allocated_here= true;
- }
+ error= ctx->start(support_I_S, support_dbug_or_support_missing_priv,
+ (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,
+ thd->variables.optimizer_trace_features);
- if (thd->opt_trace->start(support_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,
- thd->variables.optimizer_trace_features))
+ if (likely(!error))
{
- if (allocated_here)
+ if (unlikely(support_I_S) && ctx->is_started())
{
- delete thd->opt_trace;
- thd->opt_trace= NULL;
+ if (instr != NULL)
+ {
+ String buffer;
+ buffer.set_charset(system_charset_info);
+ instr->print(&buffer);
+ ctx->set_query(buffer.ptr(), buffer.length(), query_charset);
+ }
+ else
+ ctx->set_query(query, query_length, query_charset);
}
- DBUG_RETURN(false);
}
- DBUG_RETURN(true); // started all ok
+ opt_trace_disable_if_no_tables_access(thd, tbl);
+ DBUG_VOID_RETURN;
}
-void opt_trace_end(THD *thd, bool started)
+Opt_trace_start::~Opt_trace_start()
{
- DBUG_ENTER("opt_trace_end");
- if (started)
- thd->opt_trace->end();
+ DBUG_ENTER("~opt_trace_start");
+ if (likely(!error))
+ ctx->end();
DBUG_VOID_RETURN;
}
@@ -215,7 +207,7 @@ void opt_trace_end(THD *thd, bool starte
void opt_trace_print_expanded_query(THD *thd, st_select_lex *select_lex)
{
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
/**
It's hard to prove that st_select_lex::print() doesn't modify any of its
Item-s in a dangerous way. Item_int::print(), for example, modifies its
@@ -226,7 +218,7 @@ void opt_trace_print_expanded_query(THD
See also the corresponding call to "set_items_ref_array" at end of
JOIN::exec().
*/
- if (likely(trace == NULL || !trace->support_I_S()))
+ if (likely(!trace->support_I_S()))
return;
char buff[1024];
String str(buff,(uint32) sizeof(buff), system_charset_info);
@@ -243,50 +235,387 @@ void opt_trace_print_expanded_query(THD
}
-void opt_trace_set_query(Opt_trace_context *trace, const char *query,
- size_t query_length,
- const CHARSET_INFO *query_charset)
+/**
+ @name Description of trace-induced additional security checks.
+ A trace exposes information. For example if one does SELECT on a view, the
+ trace contains the view's body. So, the user should be allowed to see the
+ trace only if she/he has privilege to see the body, i.e. privilege to do SHOW
+ CREATE VIEW.
+ There are similar issues with stored procedures, functions, triggers.
+
+ We implement this by doing additional checks on SQL objects when tracing is
+ on:
+ @li stored procedures, functions, triggers: checks are done when executing
+ those objects
+ @li base tables and views.
+
+ Base tables or views are listed in some LEX::query_tables.
+ The LEX may be of the executing statement (statement executed by
+ mysql_execute_command(), or by
+ sp_lex_keeper::reset_lex_and_exec_core()), we check this LEX in the
+ constructor of Opt_trace_start.
+ Or it may be a LEX describing a view, we check this LEX when
+ opening the view (mysql_make_view()).
+
+ Those checks are greatly simplified by disabling traces in case of security
+ context changes (@see opt_trace_disable_if_no_security_context_access()).
+
+ Those checks must be done with the security context of the connected
+ user. Checks with the SUID context would be useless: assume the design is
+ that the basic user does not have DML privileges on tables, but only
+ EXECUTE on SUID-highly-privileged routines (which implement _controlled_
+ _approved_ DMLs): then the SUID context would successfully pass all
+ additional privilege checks, routine would generate tracing, and the
+ connected user would view the trace after the routine's execution, seeing
+ secret information.
+*/
+
+//@{
+
+/**
+ If the security context is not that of the connected user, inform the trace
+ system that a privilege is missing. With one exception: see below.
+
+ @param thd
+
+ This serves to eliminate the following issue.
+ Any information readable by a SELECT may theoretically end up in
+ the trace. And a SELECT may read information from other places than tables:
+ - from views (reading their bodies)
+ - from stored routines (reading their bodies)
+ - from files (reading their content), with LOAD_FILE()
+ - from the list of connections (reading their queries...), with
+ I_S.PROCESSLIST.
+ - from etc, maybe.
+ If the connected user has EXECUTE privilege on a routine which does a
+ security context change, the routine can retrieve information internally
+ (if allowed by the SUID context's privileges), and present only a portion
+ of it to the connected user. But with tracing on, all information is
+ possibly in the trace. So the connected user receives more information than
+ the routine's definer intended to provide. Fixing this issue would require
+ adding, near many privilege checks in the server, a new
+ optimizer-trace-specific check done against the connected user's context,
+ to verify that the connected user has the right to see the retrieved
+ information.
+
+ Instead, our chosen simpler solution is that if we see a security context
+ change where SUID user is not the connected user, we disable tracing. With
+ only one safe exception: if the connected user has all global privileges
+ (because then she/he can find any information anyway). By "all global
+ privileges" we mean everything but WITH GRANT OPTION (that latter one isn't
+ related to information gathering).
+
+ Read access to I_S.OPTIMIZER_TRACE by another user than the connected user
+ is restricted: @see fill_optimizer_trace_info().
+*/
+void opt_trace_disable_if_no_security_context_access(THD *thd)
{
- trace->set_query(query, query_length, query_charset);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_ENTER("opt_trace_check_disable_if_no_security_context_access");
+ if (likely(!(thd->variables.optimizer_trace &
+ Opt_trace_context::FLAG_ENABLED)) || // (1)
+ thd->system_thread) // (2)
+ {
+ /*
+ (1) We know that the routine's execution starts with "enabled=off".
+ If it stays so until the routine ends, we needn't do security checks on
+ the routine.
+ If it does not stay so, it means the definer sets it to "on" somewhere
+ in the routine's body. Then it is his conscious decision to generate
+ traces, thus it is still correct to skip the security check.
+
+ (2) Threads of the Events Scheduler have an unusual security context
+ (thd->main_security_ctx.priv_user==NULL, see comment in
+ Security_context::change_security_context()).
+ */
+ DBUG_VOID_RETURN;
+ }
+ Opt_trace_context * const trace= &thd->opt_trace;
+ if (!trace->is_started())
+ {
+ /*
+ @@optimizer_trace has "enabled=on" but trace is not started.
+ Either Opt_trace_start ctor was not called for our statement (1), or it
+ was called but at that time, the variable had "enabled=off" (2).
+
+ (1) can happen in execution of COM_FIELD_LIST on a view.
+
+ (2) suggests that the user managed to change the variable during
+ execution of the statement, and this statement is using
+ view/routine (note that we have not been able to provoke this, maybe
+ this is impossible). If it happens it is suspicious.
+
+ We disable I_S output. And we cannot do otherwise: we have no place to
+ store a possible "missing privilege" information (no Opt_trace_stmt, as
+ is_started() is false), so cannot do security checks, so cannot safely
+ do tracing, so have to disable I_S output.
+ */
+ DBUG_ASSERT(thd->get_command() == COM_FIELD_LIST);
+ trace->disable_I_S_for_this_and_children();
+ DBUG_VOID_RETURN;
+ }
+ /*
+ Note that thd->main_security_ctx.master_access is probably invariant
+ accross the life of THD: GRANT/REVOKE don't affect global privileges of an
+ existing connection, per the manual.
+ */
+ if (!(test_all_bits(thd->main_security_ctx.master_access,
+ (GLOBAL_ACLS & ~GRANT_ACL))) &&
+ (strcmp(thd->main_security_ctx.priv_user,
+ thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, thd->main_security_ctx.priv_host,
+ thd->security_ctx->priv_host)))
+ trace->missing_privilege();
+ DBUG_VOID_RETURN;
+#endif
}
-int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *cond)
+/**
+ If tracing is on, checks additional privileges on a stored routine, to make
+ sure that the user has the right to do SHOW CREATE PROCEDURE/FUNCTION. For
+ that, we use the same checks as in those SHOW commands.
+ If a privilege is missing, notifies the trace system.
+
+ This function is not redundant with
+ opt_trace_disable_if_no_security_context_access().
+ Indeed, for a SQL SECURITY INVOKER routine, there is no context change, but
+ we must still verify that the invoker can do SHOW CREATE.
+
+ For triggers, see note in sp_head::execute_trigger().
+
+ @param thd
+ @param sp routine to check
+ */
+void opt_trace_disable_if_no_stored_proc_func_access(THD *thd, sp_head *sp)
{
-#ifdef OPTIMIZER_TRACE
- DBUG_ENTER("fill_optimizer_trace_info");
- if (thd->opt_trace != NULL)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_ENTER("opt_trace_disable_if_no_stored_proc_func_access");
+ if (likely(!(thd->variables.optimizer_trace &
+ Opt_trace_context::FLAG_ENABLED)) || thd->system_thread)
+ DBUG_VOID_RETURN;
+ Opt_trace_context * const trace= &thd->opt_trace;
+ if (!trace->is_started())
{
- TABLE *table= tables->table;
- Opt_trace_info info;
+ DBUG_ASSERT(thd->get_command() == COM_FIELD_LIST);
+ trace->disable_I_S_for_this_and_children();
+ DBUG_VOID_RETURN;
+ }
+ bool full_access;
+ Security_context * const backup_thd_sctx= thd->security_ctx;
+ DBUG_PRINT("opt", ("routine: '%s'", sp->m_name.str));
+ thd->security_ctx= &thd->main_security_ctx;
+ const bool rc= check_show_routine_access(thd, sp, &full_access) ||
+ !full_access;
+ thd->security_ctx= backup_thd_sctx;
+ if (rc)
+ trace->missing_privilege();
+ DBUG_VOID_RETURN;
+#endif
+}
+
+
+/**
+ If tracing is on, checks additional privileges for a view, to make sure that
+ the user has the right to do SHOW CREATE VIEW. For that:
+ - this function checks SHOW VIEW
+ - SELECT is tested in opt_trace_disable_if_no_tables_access()
+ - SELECT + SHOW VIEW is sufficient for SHOW CREATE VIEW.
+ We also check underlying tables.
+ If a privilege is missing, notifies the trace system.
+ This function should be called when the view's underlying tables have not
+ yet been merged.
+
+ @param thd THD context
+ @param view view to check
+ @param underlying_tables underlying tables/views of 'view'
+ */
+void opt_trace_disable_if_no_view_access(THD *thd, TABLE_LIST *view,
+ TABLE_LIST *underlying_tables)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_ENTER("opt_trace_disable_if_no_view_access");
+ if (likely(!(thd->variables.optimizer_trace &
+ Opt_trace_context::FLAG_ENABLED)) || thd->system_thread)
+ DBUG_VOID_RETURN;
+ Opt_trace_context * const trace= &thd->opt_trace;
+ if (!trace->is_started())
+ {
+ DBUG_ASSERT(thd->get_command() == COM_FIELD_LIST);
+ trace->disable_I_S_for_this_and_children();
+ DBUG_VOID_RETURN;
+ }
+ DBUG_PRINT("opt", ("view: '%s'", view->table_name));
+ Security_context * const backup_table_sctx= view->security_ctx;
+ Security_context * const backup_thd_sctx= thd->security_ctx;
+ const GRANT_INFO backup_grant_info= view->grant;
+ view->security_ctx= NULL; // no SUID context for view
+ thd->security_ctx= &thd->main_security_ctx; // no SUID context for THD
+ const int rc= check_table_access(thd, SHOW_VIEW_ACL, view, false, 1, true);
+ view->security_ctx= backup_table_sctx;
+ thd->security_ctx= backup_thd_sctx;
+ view->grant= backup_grant_info;
+ if (rc)
+ {
+ trace->missing_privilege();
+ DBUG_VOID_RETURN;
+ }
+ /*
+ We needn't check SELECT privilege on this view. Some
+ opt_trace_disable_if_no_tables_access() call has or will check it.
+
+ Now we check underlying tables/views of our view:
+ */
+ opt_trace_disable_if_no_tables_access(thd, underlying_tables);
+ DBUG_VOID_RETURN;
+#endif
+}
+
+
+namespace {
+
+/**
+ If tracing is on, checks additional privileges on a list of tables/views,
+ to make sure that the user has the right to do SHOW CREATE TABLE/VIEW and
+ "SELECT *". For that:
+ - this functions checks table-level SELECT
+ - which is sufficient for SHOW CREATE TABLE and "SELECT *", if a base table
+ - if a view, if the view has not been identified as such then
+ opt_trace_disable_if_no_view_access() will be later called and check SHOW
+ VIEW; other we check SHOW VIEW here; SHOW VIEW + SELECT is sufficient for
+ SHOW CREATE VIEW.
+ If a privilege is missing, notifies the trace system.
+
+ @param thd
+ @param tbl list of tables to check
+*/
+void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_ENTER("opt_trace_disable_if_no_tables_access");
+ if (likely(!(thd->variables.optimizer_trace &
+ Opt_trace_context::FLAG_ENABLED)) || thd->system_thread)
+ DBUG_VOID_RETURN;
+ Opt_trace_context * const trace= &thd->opt_trace;
+ if (!trace->is_started())
+ {
+ DBUG_ASSERT(thd->get_command() == COM_FIELD_LIST);
+ trace->disable_I_S_for_this_and_children();
+ DBUG_VOID_RETURN;
+ }
+ Security_context * const backup_thd_sctx= thd->security_ctx;
+ thd->security_ctx= &thd->main_security_ctx;
+ const TABLE_LIST * const first_not_own_table= thd->lex->first_not_own_table();
+ for (TABLE_LIST *t= tbl;
+ t != NULL && t != first_not_own_table;
+ t= t->next_global)
+ {
+ DBUG_PRINT("opt", ("table: '%s'", t->table_name));
/*
- The list must not change during the iterator's life time. This is ok as
- the life time is only the present block which cannot change the list.
+ Anonymous derived tables (as in
+ "SELECT ... FROM (SELECT ...)") don't have their grant.privilege set.
*/
- for (Opt_trace_iterator it(thd->opt_trace) ; !it.at_end() ; it.next())
+ if (!t->is_anonymous_derived_table())
{
- it.get_value(&info);
- restore_record(table, s->default_values);
+ const GRANT_INFO backup_grant_info= t->grant;
+ Security_context * const backup_table_sctx= t->security_ctx;
+ t->security_ctx= NULL;
/*
- 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.
+ (1) check_table_access() fills t->grant.privilege.
+ (2) Because SELECT privileges can be column-based,
+ check_table_access() will return 'false' as long as there is SELECT
+ privilege on one column. But we want a table-level privilege.
*/
- 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);
- table->field[2]->store(info.missing_bytes, true);
- if (schema_table_store_record(thd, table))
- DBUG_RETURN(1);
+
+ bool rc= check_table_access(thd, SELECT_ACL, t, false, 1, true) || // (1)
+ ((t->grant.privilege & SELECT_ACL) == 0); // (2)
+ if (t->view)
+ {
+ /*
+ It's a view which has already been opened: we are executing a
+ prepared statement. The view has been unfolded in the global list of
+ tables. So underlying tables will be automatically checked in the
+ present function, but we need an explicit check of SHOW VIEW:
+ */
+ rc|= check_table_access(thd, SHOW_VIEW_ACL, t, false, 1, true);
+ }
+ t->security_ctx= backup_table_sctx;
+ t->grant= backup_grant_info;
+ if (rc)
+ {
+ trace->missing_privilege();
+ break;
+ }
}
}
+ thd->security_ctx= backup_thd_sctx;
+ DBUG_VOID_RETURN;
+#endif
+}
+
+} // namespace
+
+//@}
+
+
+int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *cond)
+{
+#ifdef OPTIMIZER_TRACE
+ TABLE *table= tables->table;
+ Opt_trace_info info;
+
+ /*
+ When executing a routine which is SQL SECURITY DEFINER, opt-trace specific
+ checks are done with the connected user's privileges; this isn't
+ respecting the meaning of SQL SECURITY DEFINER. If a highly privileged
+ user doesn't know that, he may confidently execute a routine, while this
+ routine nastily uses the connected user's privileges to be allowed to do
+ tracing and gain knowledge about secret objects.
+ This possibility is prevented, by making I_S.OPTIMIZER_TRACE look empty
+ when read from a security context which isn't the connected user's
+ context; with an exception if the SUID security context has all
+ global privileges (in which case the nasty definer has anyway all rights
+ to trace everything).
+
+ Objects which are SQL SECURITY INVOKER are not considered here: with or
+ without optimizer trace, a highly privileged user must always inspect the
+ body of such object before invoking it.
+ */
+ if (!test_all_bits(thd->security_ctx->master_access,
+ (GLOBAL_ACLS & ~GRANT_ACL)) &&
+ (strcmp(thd->main_security_ctx.priv_user,
+ thd->security_ctx->priv_user) ||
+ my_strcasecmp(system_charset_info, thd->main_security_ctx.priv_host,
+ thd->security_ctx->priv_host)))
+ return 0;
+ /*
+ The list must not change during the iterator's life time. This is ok as
+ the life time is only the present block which cannot change the list.
+ */
+ for (Opt_trace_iterator it(&thd->opt_trace) ; !it.at_end() ; it.next())
+ {
+ it.get_value(&info);
+ restore_record(table, s->default_values);
+ /*
+ 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);
+ table->field[2]->store(info.missing_bytes, true);
+ table->field[3]->store(info.missing_priv, true);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
- DBUG_RETURN(0);
+ return 0;
#else
my_error(ER_FEATURE_DISABLED, MYF(0), "optimizer trace",
- "-DOPTIMIZER_TRACE=1 or --with-optimizer-trace");
+ "-DOPTIMIZER_TRACE=1");
return 1;
#endif
}
@@ -299,6 +628,8 @@ ST_FIELD_INFO optimizer_trace_info[]=
{"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
{"MISSING_BYTES_BEYOND_MAX_MEM_SIZE", 20, MYSQL_TYPE_LONG,
0, false, NULL, SKIP_OPEN_TABLE},
+ {"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY,
+ 0, false, NULL, SKIP_OPEN_TABLE},
{NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
};
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc 2011-03-09 20:54:55 +0000
+++ b/sql/sp_head.cc 2011-05-04 20:53:28 +0000
@@ -39,6 +39,7 @@
#include "sql_parse.h" // cleanup_items
#include "sql_base.h" // close_thread_tables
#include "transaction.h" // trans_commit_stmt
+#include "opt_trace.h" // opt_trace_disable_etc
/*
Sufficient max length of printed destinations and frame offsets (all uints).
@@ -1246,6 +1247,8 @@ sp_head::execute(THD *thd, bool merge_da
if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
+ opt_trace_disable_if_no_security_context_access(thd);
+
/* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
@@ -1690,6 +1693,13 @@ sp_head::execute_trigger(THD *thd,
m_security_ctx.restore_security_context(thd, save_ctx);
DBUG_RETURN(TRUE);
}
+ /*
+ Optimizer trace note: we needn't explicitely test here that the connected
+ user has TRIGGER privilege: assume he doesn't have it; two possibilities:
+ - connected user == definer: then we threw an error just above;
+ - connected user != definer: then in sp_head::execute(), when checking the
+ security context we will disable tracing.
+ */
#endif // NO_EMBEDDED_ACCESS_CHECKS
/*
@@ -1927,6 +1937,8 @@ sp_head::execute_function(THD *thd, Item
thd->variables.option_bits&= ~OPTION_BIN_LOG;
}
+ opt_trace_disable_if_no_stored_proc_func_access(thd, this);
+
/*
Switch to call arena/mem_root so objects like sp_cursor or
Item_cache holders for case expressions can be allocated on it.
@@ -2171,6 +2183,8 @@ sp_head::execute_procedure(THD *thd, Lis
err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
#endif
+ opt_trace_disable_if_no_stored_proc_func_access(thd, this);
+
if (!err_status)
err_status= execute(thd, TRUE);
@@ -2951,20 +2965,36 @@ sp_lex_keeper::reset_lex_and_exec_core(T
reinit_stmt_before_use(thd, m_lex);
if (open_tables)
- res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
-
- if (!res)
{
- res= instr->exec_core(thd, nextp);
- DBUG_PRINT("info",("exec_core returned: %d", res));
- }
+ /*
+ IF, CASE, DECLARE, SET, RETURN, have 'open_tables' true; they may
+ have a subquery in parameter and are worth tracing. They don't
+ correspond to a SQL command so we pretend that they are SQLCOM_SELECT.
+ */
+ Opt_trace_start ots(thd, m_lex->query_tables,
+ SQLCOM_SELECT, NULL, 0, instr,
+ thd->variables.character_set_client);
+ Opt_trace_object trace_command(&thd->opt_trace);
+ Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
- /*
- Call after unit->cleanup() to close open table
- key read.
- */
- if (open_tables)
- {
+ /*
+ Check whenever we have access to tables for this statement
+ and open and lock them before executing instructions core function.
+ */
+ res= (check_table_access(thd, SELECT_ACL, m_lex->query_tables, FALSE,
+ UINT_MAX, FALSE) ||
+ open_and_lock_tables(thd, m_lex->query_tables, TRUE, 0));
+
+ if (!res)
+ {
+ res= instr->exec_core(thd, nextp);
+ DBUG_PRINT("info",("exec_core returned: %d", res));
+ }
+
+ /*
+ Call after unit->cleanup() to close open table
+ key read.
+ */
m_lex->unit.cleanup();
/* Here we also commit or rollback the current statement. */
if (! thd->in_sub_stmt)
@@ -2982,6 +3012,11 @@ sp_lex_keeper::reset_lex_and_exec_core(T
else if (! thd->in_sub_stmt)
thd->mdl_context.release_statement_locks();
}
+ else
+ {
+ res= instr->exec_core(thd, nextp);
+ DBUG_PRINT("info",("exec_core returned: %d", res));
+ }
if (m_lex->query_tables_own_last)
{
@@ -3032,23 +3067,6 @@ sp_lex_keeper::reset_lex_and_exec_core(T
sp_instr class functions
*/
-int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
-{
- int result;
-
- /*
- Check whenever we have access to tables for this statement
- and open and lock them before executing instructions core function.
- */
- if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)
- || open_and_lock_tables(thd, tables, TRUE, 0))
- result= -1;
- else
- result= 0;
-
- return result;
-}
-
uint sp_instr::get_cont_dest()
{
return (m_ip+1);
=== modified file 'sql/sp_head.h'
--- a/sql/sp_head.h 2011-03-09 20:54:55 +0000
+++ b/sql/sp_head.h 2011-05-04 20:53:28 +0000
@@ -585,17 +585,6 @@ public:
virtual int execute(THD *thd, uint *nextp) = 0;
/**
- Execute <code>open_and_lock_tables()</code> for this statement.
- Open and lock the tables used by this statement, as a pre-requisite
- to execute the core logic of this instruction with
- <code>exec_core()</code>.
- @param thd the current thread
- @param tables the list of tables to open and lock
- @return zero on success, non zero on failure.
- */
- int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
-
- /**
Get the continuation destination of this instruction.
@return the continuation destination
*/
@@ -1354,6 +1343,8 @@ sp_prepare_func_item(THD* thd, Item **it
bool
sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr);
+bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access);
+
/**
@} (end of group Stored_Routines)
*/
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_class.cc 2011-05-04 20:53:28 +0000
@@ -56,7 +56,6 @@
#include "sp_cache.h"
#include "transaction.h"
#include "debug_sync.h"
-#include "opt_trace.h"
#include "sql_parse.h" // is_update_query
#include "sql_callback.h"
#include "lock.h"
@@ -529,7 +528,6 @@ THD::THD(bool enable_plugins)
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
m_enable_plugins(enable_plugins),
- opt_trace(NULL),
main_warning_info(0)
{
ulong tmp;
@@ -1126,7 +1124,6 @@ THD::~THD()
mysql_audit_free_thd(this);
#endif
- delete opt_trace;
free_root(&main_mem_root, MYF(0));
DBUG_VOID_RETURN;
}
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2011-03-21 17:55:41 +0000
+++ b/sql/sql_class.h 2011-05-04 20:53:28 +0000
@@ -38,7 +38,7 @@
#include "violite.h" /* vio_is_connected */
#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA,
THR_LOCK_INFO */
-
+#include "opt_trace.h" /* Opt_trace_context */
class Reprepare_observer;
class Relay_log_info;
@@ -1473,8 +1473,6 @@ private:
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
-class Opt_trace_context;
-
/**
@class THD
For each client connection we create a separate thread with THD serving as
@@ -2822,7 +2820,7 @@ public:
*/
Internal_error_handler *pop_internal_handler();
- Opt_trace_context *opt_trace; ///< optimizer trace of current statement
+ Opt_trace_context opt_trace; ///< optimizer trace of current statement
/**
Raise an exception condition.
@param code the MYSQL_ERRNO error code of the error
=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc 2011-04-05 07:34:13 +0000
+++ b/sql/sql_delete.cc 2011-05-04 20:53:28 +0000
@@ -193,7 +193,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
DBUG_RETURN(TRUE);
{ // Enter scope for optimizer trace wrapper
- Opt_trace_object wrapper(thd->opt_trace);
+ Opt_trace_object wrapper(&thd->opt_trace);
wrapper.add_utf8_table(table);
if ((select && select->check_quick(thd, safe_update, limit)) || !limit)
=== modified file 'sql/sql_help.cc'
--- a/sql/sql_help.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_help.cc 2011-05-04 20:53:28 +0000
@@ -580,7 +580,7 @@ SQL_SELECT *prepare_simple_select(THD *t
SQL_SELECT *res= make_select(table, 0, 0, cond, 0, error);
// Wrapper for correct JSON in optimizer trace
- Opt_trace_object wrapper(thd->opt_trace);
+ Opt_trace_object wrapper(&thd->opt_trace);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)) ||
(res && res->quick && res->quick->reset()))
{
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_parse.cc 2011-05-04 20:53:28 +0000
@@ -419,23 +419,14 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_INSTALL_PLUGIN]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]= CF_CHANGES_DATA;
- // (1): without it, a procedure's substatements would not be traced.
- sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE |
- CF_CAN_GENERATE_ROW_EVENTS |
- CF_OPTIMIZER_TRACE; // (1)
/*
- (1): without it, the executed statement would not be traced. Execution of
- SQLCOM_EXECUTE calls mysql_execute_command() on executed command, which
- will check whether that executed command can actually be traced.
+ (1): without it, in "CALL some_proc((subq))", subquery would not be
+ traced.
*/
- sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS |
+ sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE |
+ CF_CAN_GENERATE_ROW_EVENTS |
CF_OPTIMIZER_TRACE; // (1)
- /*
- (1): without it, the prepared statement would not be traced.
- check_prepared_statement() will check whether prepared command can
- actually be traced.
- */
- sql_command_flags[SQLCOM_PREPARE]= CF_OPTIMIZER_TRACE; // (1)
+ sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
/*
The following admin table operations are allowed
@@ -2019,14 +2010,12 @@ mysql_execute_command(THD *thd)
status_var_increment(thd->status_var.com_stat[lex->sql_command]);
- 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_start ots(thd, all_tables, lex->sql_command,
+ thd->query(), thd->query_length(), NULL,
+ thd->variables.character_set_client);
- Opt_trace_object trace_command(thd->opt_trace);
- Opt_trace_array trace_command_steps(thd->opt_trace, "steps");
+ Opt_trace_object trace_command(&thd->opt_trace);
+ Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
@@ -4485,10 +4474,6 @@ finish:
thd->mdl_context.release_statement_locks();
}
- 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 || thd->is_error());
}
=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_prepare.cc 2011-05-04 20:53:28 +0000
@@ -1969,15 +1969,12 @@ static bool check_prepared_statement(Pre
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_start ots(thd, tables, sql_command,
+ thd->query(), thd->query_length(), NULL,
+ thd->variables.character_set_client);
-
- Opt_trace_object trace_command(thd->opt_trace);
- Opt_trace_array trace_command_steps(thd->opt_trace, "steps");
+ Opt_trace_object trace_command(&thd->opt_trace);
+ Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
switch (sql_command) {
case SQLCOM_REPLACE:
@@ -2021,8 +2018,7 @@ static bool check_prepared_statement(Pre
if (res == 2)
{
/* Statement and field info has already been sent */
- res= FALSE;
- goto end;
+ DBUG_RETURN(FALSE);
}
break;
case SQLCOM_CREATE_TABLE:
@@ -2033,8 +2029,7 @@ static bool check_prepared_statement(Pre
if (lex->create_view_mode == VIEW_ALTER)
{
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
- res= true;
- goto end;
+ goto error;
}
res= mysql_test_create_view(stmt);
break;
@@ -2107,19 +2102,15 @@ static bool check_prepared_statement(Pre
{
/* All other statements are not supported yet. */
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
- res= true;
- goto end;
+ goto error;
}
break;
}
if (res == 0)
- 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);
+ DBUG_RETURN(stmt->is_sql_prepare() ?
+ FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
+error:
+ DBUG_RETURN(TRUE);
}
/**
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2011-04-14 11:49:41 +0000
+++ b/sql/sql_select.cc 2011-05-04 20:53:28 +0000
@@ -562,7 +562,7 @@ JOIN::prepare(Item ***rref_pointer_array
if (thd->derived_tables_processing)
select_lex->exclude_from_table_unique_test= TRUE;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_prepare(trace, "join_preparation");
trace_prepare.add_select_number(select_lex->select_number);
@@ -998,7 +998,7 @@ bool resolve_subquery(THD *thd, JOIN *jo
}
}
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
if (subq_predicate_substype == Item_subselect::IN_SUBS)
{
{
@@ -1823,7 +1823,7 @@ JOIN::optimize()
thd_proc_info(thd, "optimizing");
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_optimize(trace, "join_optimization");
trace_optimize.add_select_number(select_lex->select_number);
@@ -2825,7 +2825,7 @@ JOIN::save_join_tab()
void
JOIN::exec()
{
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_exec(trace, "join_execution");
trace_exec.add_select_number(select_lex->select_number);
@@ -3468,8 +3468,7 @@ JOIN::exec()
*/
if (items0 && ((thd->lex->describe & DESCRIBE_EXTENDED)
#ifdef OPTIMIZER_TRACE
- || (thd->opt_trace != NULL &&
- thd->opt_trace->support_I_S())
+ || trace->support_I_S()
#endif
) &&
(select_lex->linkage == DERIVED_TABLE_TYPE ||
@@ -4157,7 +4156,7 @@ bool JOIN::flatten_subqueries()
Item_exists_subselect **subq;
Item_exists_subselect **subq_end;
bool outer_join_objection= FALSE;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
DBUG_ENTER("JOIN::flatten_subqueries");
if (sj_subselects.elements() == 0)
@@ -4478,7 +4477,7 @@ bool pull_out_semijoin_tables(JOIN *join
DBUG_RETURN(FALSE);
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
if (join->select_lex->sj_nests.elements == 0)
DBUG_RETURN(0);
@@ -4725,7 +4724,7 @@ make_join_statistics(JOIN *join, TABLE_L
table_map outer_join=0;
SARGABLE_PARAM *sargables= 0;
JOIN_TAB *stat_vector[MAX_TABLES+1];
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
DBUG_ENTER("make_join_statistics");
table_count=join->tables;
@@ -5275,7 +5274,7 @@ static bool optimize_semijoin_nests(JOIN
DBUG_ENTER("optimize_semijoin_nests");
List_iterator<TABLE_LIST> sj_list_it(join->select_lex->sj_nests);
TABLE_LIST *sj_nest;
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
while ((sj_nest= sj_list_it++))
{
@@ -6514,7 +6513,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR
(void) set_dynamic(keyuse, &key_end, i);
keyuse->elements=i;
}
- print_keyuse_array(thd->opt_trace, keyuse);
+ print_keyuse_array(&thd->opt_trace, keyuse);
return FALSE;
}
@@ -6703,7 +6702,7 @@ add_group_and_distinct_keys(JOIN *join,
if (!possible_keys.is_clear_all() &&
!(possible_keys == join_tab->const_keys))
{
- trace_indices_added_group_distinct(join->thd->opt_trace, join_tab,
+ trace_indices_added_group_distinct(&join->thd->opt_trace, join_tab,
possible_keys, cause);
join_tab->const_keys.merge(possible_keys);
}
@@ -6728,7 +6727,7 @@ static void trace_indices_added_group_di
const char* cause)
{
#ifdef OPTIMIZER_TRACE
- if (likely(trace == NULL) || !trace->is_started())
+ if (likely(!trace->is_started()))
return;
KEY *key_info= join_tab->table->key_info;
@@ -7151,7 +7150,7 @@ best_access_path(JOIN *join,
table_map best_ref_depends_map= 0;
double tmp;
bool best_uses_jbuf= FALSE;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Loose_scan_opt loose_scan_opt;
DBUG_ENTER("best_access_path");
@@ -7530,7 +7529,6 @@ best_access_path(JOIN *join,
} /* not ft_key */
trace_access_idx.add("records", records).add("cost", tmp);
- /** @todo trace quick_matches_more_parts etc? */
if (tmp < best_time - records/(double) TIME_FOR_COMPARE ||
(quick_matches_more_parts &&
quick_records < best_quick_records))
@@ -7805,8 +7803,8 @@ choose_plan(JOIN *join, table_map join_t
jtab_sort_func, (void*)join->emb_sjm_nest);
join->cur_sj_inner_tables= 0;
- Opt_trace_object wrapper(join->thd->opt_trace);
- Opt_trace_array trace_plan(join->thd->opt_trace, "considered_execution_plans",
+ Opt_trace_object wrapper(&join->thd->opt_trace);
+ Opt_trace_array trace_plan(&join->thd->opt_trace, "considered_execution_plans",
Opt_trace_context::GREEDY_SEARCH);
if (straight_join)
optimize_straight_join(join, join_tables);
@@ -8016,7 +8014,7 @@ optimize_straight_join(JOIN *join, table
double read_time= 0.0;
POSITION loose_scan_pos;
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
Opt_trace_object trace_table(trace);
@@ -8487,7 +8485,7 @@ best_extension_by_limited_search(JOIN
DBUG_ENTER("best_extension_by_limited_search");
THD *thd= join->thd;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
if (thd->killed) // Abort
DBUG_RETURN(TRUE);
@@ -8861,7 +8859,7 @@ static bool fix_semijoin_strategies_for_
{
table_map remaining_tables= 0;
table_map handled_tabs= 0;
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
DBUG_ENTER("fix_semijoin_strategies_for_picked_join_order");
if (join->select_lex->sj_nests.is_empty())
@@ -9955,7 +9953,7 @@ static bool make_join_select(JOIN *join,
*/
table_map used_tables= 0;
table_map save_used_tables= 0;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_conditions(trace,
"attaching_conditions_to_tables");
@@ -10145,10 +10143,9 @@ static bool make_join_select(JOIN *join,
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
- Opt_trace_object trace_one_table(thd->opt_trace);
+ Opt_trace_object trace_one_table(trace);
trace_one_table.add_utf8_table(tab->table);
- Opt_trace_object trace_table(join->thd->opt_trace,
- "rechecking_index_usage");
+ Opt_trace_object trace_table(trace, "rechecking_index_usage");
/* Join with outer join condition */
Item *orig_cond=sel->cond;
@@ -10273,7 +10270,7 @@ static bool make_join_select(JOIN *join,
for (uint i= join->const_tables ; i < join->tables ; i++)
{
const JOIN_TAB *tab= join->join_tab+i;
- Opt_trace_object trace_one_table(thd->opt_trace);
+ Opt_trace_object trace_one_table(trace);
trace_one_table.add_utf8_table(tab->table);
trace_one_table.add("attached", tab->select_cond);
}
@@ -11473,7 +11470,7 @@ make_join_readinfo(JOIN *join, ulonglong
uint last_sjm_table= MAX_TABLES;
DBUG_ENTER("make_join_readinfo");
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
Opt_trace_object wrapper(trace);
Opt_trace_array trace_refine_plan(trace, "refine_plan");
@@ -14147,7 +14144,7 @@ void optimize_wo_join_buffering(JOIN *jo
double cost, outer_fanout, inner_fanout= 1.0;
table_map reopt_remaining_tables= last_remaining_tables;
uint i;
- Opt_trace_context * const trace= join->thd->opt_trace;
+ Opt_trace_context * const trace= &join->thd->opt_trace;
DBUG_ENTER("optimize_wo_join_buffering");
Opt_trace_object trace_recompute(trace, "recompute_best_access_paths");
@@ -14272,7 +14269,7 @@ void advance_sj_state(JOIN *join, table_
TABLE_LIST *emb_sj_nest= new_join_tab->emb_sj_nest;
POSITION *pos= join->positions + idx;
THD *thd= join->thd;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
/* Add this table to the join prefix */
remaining_tables &= ~new_join_tab->table->map;
@@ -14892,7 +14889,7 @@ optimize_cond(JOIN *join, Item *conds, L
bool build_equalities, Item::cond_result *cond_value)
{
THD *thd= join->thd;
- Opt_trace_context * const trace= thd->opt_trace;
+ Opt_trace_context * const trace= &thd->opt_trace;
DBUG_ENTER("optimize_cond");
if (conds)
@@ -18788,12 +18785,10 @@ join_init_quick_read_record(JOIN_TAB *ta
*/
#ifdef OPTIMIZER_TRACE
- Opt_trace_context * const trace= tab->join->thd->opt_trace;
- const bool repeated_trace_enabled= trace ?
- trace->feature_enabled(Opt_trace_context::DYNAMIC_RANGE) :
- false;
- const bool disable_trace=
- (tab->select->traced_before && !repeated_trace_enabled);
+ Opt_trace_context * const trace= &tab->join->thd->opt_trace;
+ const bool disable_trace=
+ tab->select->traced_before &&
+ !trace->feature_enabled(Opt_trace_context::DYNAMIC_RANGE);
Opt_trace_disable_I_S disable_trace_wrapper(trace, disable_trace);
tab->select->traced_before= true;
@@ -20440,6 +20435,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
ref_key_parts= select->quick->used_key_parts;
}
+ Opt_trace_context * const trace= &tab->join->thd->opt_trace;
+
if (ref_key >= 0)
{
/*
@@ -20506,7 +20503,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
key_map new_ref_key_map; // Force the creation of quick select
new_ref_key_map.set_bit(new_ref_key); // only for new_ref_key.
- Opt_trace_context * const trace= tab->join->thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_recest(trace,
"records_estimation_for_index_ordering");
@@ -20561,7 +20557,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,OR
{
if (table->quick_keys.is_set(best_key) && best_key != ref_key)
{
- Opt_trace_context * const trace= join->thd->opt_trace;
Opt_trace_object trace_wrapper(trace);
Opt_trace_object trace_recest(trace,
"records_estimation_for_index_ordering");
=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_update.cc 2011-05-04 20:53:28 +0000
@@ -405,7 +405,7 @@ int mysql_update(THD *thd,
select= make_select(table, 0, 0, conds, 0, &error);
{ // Enter scope for optimizer trace wrapper
- Opt_trace_object wrapper(thd->opt_trace);
+ Opt_trace_object wrapper(&thd->opt_trace);
wrapper.add_utf8_table(table);
if (error || !limit ||
=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sql_view.cc 2011-05-04 20:53:28 +0000
@@ -32,7 +32,7 @@
#include "sp_head.h"
#include "sp_cache.h"
#include "datadict.h" // dd_frm_type()
-#include "opt_trace.h"
+#include "opt_trace.h" // opt_trace_disable_etc
#define MD5_BUFF_LENGTH 33
@@ -1078,6 +1078,12 @@ bool mysql_make_view(THD *thd, File_pars
not changed since PREPARE or the previous execution: the only case
when this information is changed is execution of UPDATE on a view, but
the original want_access is restored in its end.
+
+ Optimizer trace: because tables have been unfolded already, they are
+ in lex->query_tables of the statement using the view. So privileges on
+ them are checked as done for explicitely listed tables, in constructor
+ of Opt_trace_start. Security context change is checked in
+ prepare_security() below.
*/
if (!table->prelocking_placeholder && table->prepare_security(thd))
{
@@ -1133,8 +1139,8 @@ bool mysql_make_view(THD *thd, File_pars
table->definer.user.str= table->definer.host.str= 0;
table->definer.user.length= table->definer.host.length= 0;
- Opt_trace_object trace_wrapper(thd->opt_trace);
- Opt_trace_object trace_view(thd->opt_trace, "view");
+ Opt_trace_object trace_wrapper(&thd->opt_trace);
+ Opt_trace_object trace_view(&thd->opt_trace, "view");
// 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).
@@ -1288,23 +1294,27 @@ bool mysql_make_view(THD *thd, File_pars
underlying tables.
Skip this step if we are opening view for prelocking only.
*/
- if (!table->prelocking_placeholder &&
- (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
+ if (!table->prelocking_placeholder)
{
- if (check_table_access(thd, SELECT_ACL, view_tables, FALSE,
- UINT_MAX, TRUE) &&
- check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, TRUE))
+ // If executing prepared statement: see "Optimizer trace" note above.
+ opt_trace_disable_if_no_view_access(thd, table, view_tables);
+
+ if (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe)
{
- my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
- goto err;
+ if (check_table_access(thd, SELECT_ACL, view_tables, FALSE,
+ UINT_MAX, TRUE) &&
+ check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, TRUE))
+ {
+ my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
+ goto err;
+ }
+ }
+ else if ((old_lex->sql_command == SQLCOM_SHOW_CREATE) &&
+ !table->belong_to_view)
+ {
+ if (check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, FALSE))
+ goto err;
}
- }
- else if (!table->prelocking_placeholder &&
- (old_lex->sql_command == SQLCOM_SHOW_CREATE) &&
- !table->belong_to_view)
- {
- if (check_table_access(thd, SHOW_VIEW_ACL, table, FALSE, UINT_MAX, FALSE))
- goto err;
}
if (!(table->view_tables=
=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc 2011-03-21 17:55:41 +0000
+++ b/sql/sys_vars.cc 2011-05-04 20:53:28 +0000
@@ -1530,8 +1530,7 @@ static Sys_var_flagset Sys_optimizer_tra
static bool optimizer_trace_update(sys_var *self, THD *thd,
enum_var_type type)
{
- if (thd->opt_trace != NULL)
- thd->opt_trace->reset();
+ thd->opt_trace.reset();
return false;
}
=== modified file 'sql/table.cc'
--- a/sql/table.cc 2011-03-17 09:47:50 +0000
+++ b/sql/table.cc 2011-05-04 20:53:28 +0000
@@ -4232,6 +4232,7 @@ bool TABLE_LIST::prepare_security(THD *t
if (prepare_view_securety_context(thd))
DBUG_RETURN(TRUE);
thd->security_ctx= find_view_security_context(thd);
+ opt_trace_disable_if_no_security_context_access(thd);
while ((tbl= tb++))
{
DBUG_ASSERT(tbl->referencing_view);
=== modified file 'unittest/gunit/opt_trace-t.cc'
--- a/unittest/gunit/opt_trace-t.cc 2011-04-13 15:36:01 +0000
+++ b/unittest/gunit/opt_trace-t.cc 2011-05-04 20:53:28 +0000
@@ -69,6 +69,7 @@ void do_check_json_compliance(const char
// Send the trace to this new process' stdin:
FILE *fd= popen(python_cmd, "w");
ASSERT_TRUE(NULL != fd);
+ ASSERT_NE(0U, length); // empty is not compliant
ASSERT_EQ(1U, fwrite(str, length, 1, fd));
int rc= pclose(fd);
rc= WEXITSTATUS(rc);
@@ -109,8 +110,9 @@ TEST_F(TraceContentTest, ConstructAndDes
/** Test empty trace */
TEST_F(TraceContentTest, Empty)
{
- ASSERT_FALSE(trace.start(YES_FOR_THIS, false, false, -1, 1, ULONG_MAX,
+ ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
all_features));
+ EXPECT_TRUE(trace.is_started());
EXPECT_TRUE(trace.support_I_S());
/*
Add at least an object to it. A really empty trace ("") is not
@@ -135,6 +137,7 @@ TEST_F(TraceContentTest, Empty)
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
/* Should be no more traces */
it.next();
@@ -145,7 +148,7 @@ TEST_F(TraceContentTest, Empty)
/** Test normal usage */
TEST_F(TraceContentTest, NormalUsage)
{
- ASSERT_FALSE(trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -196,6 +199,7 @@ TEST_F(TraceContentTest, NormalUsage)
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_TRUE(it.at_end());
@@ -208,7 +212,7 @@ TEST_F(TraceContentTest, NormalUsage)
*/
TEST_F(TraceContentTest, Tail)
{
- ASSERT_FALSE(trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -259,6 +263,7 @@ TEST_F(TraceContentTest, Tail)
EXPECT_EQ((void *)0, info.query_ptr);
EXPECT_EQ(0U, info.query_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
EXPECT_EQ(0, strcmp(expected + sizeof(expected) - 1 - 40, tail));
it.next();
@@ -269,7 +274,7 @@ TEST_F(TraceContentTest, Tail)
/** Test reaction to malformed JSON (object with value without key) */
TEST_F(TraceContentTest, BuggyObject)
{
- ASSERT_FALSE(trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -317,6 +322,7 @@ TEST_F(TraceContentTest, BuggyObject)
EXPECT_STREQ(expected, info.trace_ptr);
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_TRUE(it.at_end());
@@ -326,7 +332,7 @@ TEST_F(TraceContentTest, BuggyObject)
/** Test reaction to malformed JSON (array with value with key) */
TEST_F(TraceContentTest, BuggyArray)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -363,6 +369,7 @@ TEST_F(TraceContentTest, BuggyArray)
EXPECT_STREQ(expected, info.trace_ptr);
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_TRUE(it.at_end());
@@ -370,9 +377,9 @@ TEST_F(TraceContentTest, BuggyArray)
/** Test Opt_trace_disable_I_S */
-TEST_F(TraceContentTest, DisableIS)
+TEST_F(TraceContentTest, DisableISWithObject)
{
- ASSERT_FALSE(trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -390,6 +397,13 @@ TEST_F(TraceContentTest, DisableIS)
/* don't disable... but above layer is stronger */
Opt_trace_disable_I_S otd2(&trace, false);
oto2.add("another key inside", 5LL);
+ // disabling should apply to substatements too:
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto3(&trace);
+ }
+ trace.end();
}
ota.add_alnum("one string element");
ota.add(true);
@@ -429,16 +443,71 @@ TEST_F(TraceContentTest, DisableIS)
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_TRUE(it.at_end());
}
+
+/** Test Opt_trace_context::disable_I_S_for_this_and_children */
+TEST_F(TraceContentTest, DisableISWithCall)
+{
+ // Test that it disables even before any start()
+ trace.disable_I_S_for_this_and_children();
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto(&trace);
+ {
+ Opt_trace_array ota(&trace, "one array");
+ ota.add(200.4);
+ {
+ Opt_trace_object oto1(&trace);
+ oto1.add_alnum("one key", "one value").
+ add("another key", 100LL);
+ oto1.add("a third key", false);
+ Opt_trace_object oto2(&trace, "a fourth key");
+ oto2.add("key inside", 1LL);
+ // disabling should apply to substatements too:
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto3(&trace);
+ }
+ trace.end();
+ /* don't disable... but above layer is stronger */
+ Opt_trace_disable_I_S otd2(&trace, false);
+ oto2.add("another key inside", 5LL);
+ // disabling should apply to substatements too:
+ ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto4(&trace);
+ }
+ trace.end();
+ }
+ ota.add_alnum("one string element");
+ ota.add(true);
+ }
+ oto.add("yet another key", -1000LL);
+ {
+ Opt_trace_array ota(&trace, "another array");
+ ota.add(1LL).add(2LL).add(3LL).add(4LL);
+ }
+ }
+ trace.end();
+ trace.restore_I_S();
+ Opt_trace_iterator it(&trace);
+ ASSERT_TRUE(it.at_end());
+}
+
+
/** Helper for Trace_settings_test.offset */
void make_one_trace(Opt_trace_context *trace, const char *name,
long offset, long limit)
{
- ASSERT_FALSE(trace->start(YES_FOR_THIS, true, false, offset, limit,
+ ASSERT_FALSE(trace->start(true, false, true, false, offset, limit,
ULONG_MAX, all_features));
{
Opt_trace_object oto(trace);
@@ -539,8 +608,8 @@ TEST_F(TraceContentTest, Offset)
/** Test truncation by max_mem_size */
TEST_F(TraceContentTest, MaxMemSize)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -1, 1,
- 1000 /* max_mem_size */, all_features));
+ ASSERT_EQ(false, trace.start(true, false, false, false, -1,
+ 1, 1000 /* max_mem_size */, all_features));
/* make a "long" trace */
{
Opt_trace_object oto(&trace);
@@ -567,6 +636,7 @@ TEST_F(TraceContentTest, MaxMemSize)
*/
EXPECT_EQ(996U, info.trace_length);
EXPECT_EQ(1027U, info.missing_bytes); // 996+1027=2023
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
EXPECT_EQ(0, strncmp(expected, info.trace_ptr, sizeof(expected) - 1));
it.next();
@@ -579,8 +649,8 @@ TEST_F(TraceContentTest, MaxMemSize)
TEST_F(TraceContentTest, MaxMemSize2)
{
Opt_trace_context trace;
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -2, 2,
- 21 /* max_mem_size */, all_features));
+ ASSERT_EQ(false, trace.start(true, false, false, false, -2,
+ 2, 21 /* max_mem_size */, all_features));
/* make a "long" trace */
{
Opt_trace_object oto(&trace);
@@ -588,8 +658,8 @@ TEST_F(TraceContentTest, MaxMemSize2)
}
trace.end();
/* A second similar trace */
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -2, 2, 21,
- all_features));
+ ASSERT_EQ(false, trace.start(true, false, false, false, -2,
+ 2, 21, all_features));
{
Opt_trace_object oto(&trace);
oto.add_alnum("some key2", "make it long");
@@ -601,6 +671,7 @@ TEST_F(TraceContentTest, MaxMemSize2)
it.get_value(&info);
EXPECT_EQ(17U, info.trace_length);
EXPECT_EQ(16U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_FALSE(it.at_end());
@@ -614,8 +685,8 @@ TEST_F(TraceContentTest, MaxMemSize2)
3rd trace; the first one should automatically be purged, thus the 3rd
should have a bit of room.
*/
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -2, 2, 21,
- all_features));
+ ASSERT_EQ(false, trace.start(true, false, false, false, -2,
+ 2, 21, all_features));
{
Opt_trace_object oto(&trace);
oto.add_alnum("some key3", "make it long");
@@ -626,6 +697,7 @@ TEST_F(TraceContentTest, MaxMemSize2)
it2.get_value(&info);
EXPECT_EQ(0U, info.trace_length);
EXPECT_EQ(33U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it2.next();
it2.get_value(&info);
@@ -635,6 +707,7 @@ TEST_F(TraceContentTest, MaxMemSize2)
*/
EXPECT_EQ(14U, info.trace_length);
EXPECT_EQ(19U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
it2.next();
ASSERT_TRUE(it2.at_end());
}
@@ -674,7 +747,7 @@ void open_object(uint count, Opt_trace_c
/// Test reaction to out-of-memory condition in trace buffer
TEST_F(TraceContentTest, OOMinBuffer)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, false, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -692,6 +765,7 @@ TEST_F(TraceContentTest, OOMinBuffer)
Opt_trace_info info;
it.get_value(&info);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
it.next();
ASSERT_TRUE(it.at_end());
EXPECT_TRUE(oom);
@@ -701,7 +775,7 @@ TEST_F(TraceContentTest, OOMinBuffer)
/// Test reaction to out-of-memory condition in book-keeping data structures
TEST_F(TraceContentTest, OOMinBookKeeping)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, false, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -713,6 +787,7 @@ TEST_F(TraceContentTest, OOMinBookKeepin
Opt_trace_info info;
it.get_value(&info);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
it.next();
ASSERT_TRUE(it.at_end());
EXPECT_TRUE(oom);
@@ -765,7 +840,7 @@ TEST_F(TraceContentTest, OOMinPurge)
/** Test filtering by feature */
TEST_F(TraceContentTest, FilteringByFeature)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, false, false, -1, 1, ULONG_MAX,
Opt_trace_context::MISC));
{
Opt_trace_object oto(&trace);
@@ -818,6 +893,7 @@ TEST_F(TraceContentTest, FilteringByFeat
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
ASSERT_TRUE(it.at_end());
@@ -827,7 +903,7 @@ TEST_F(TraceContentTest, FilteringByFeat
/** Test escaping of characters */
TEST_F(TraceContentTest, Escaping)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
// All ASCII 0-127 chars are valid UTF8 encodings
char all_chars[130];
@@ -857,6 +933,7 @@ TEST_F(TraceContentTest, Escaping)
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
EXPECT_EQ(sizeof(all_chars), info.query_length);
// we get the query unescaped, verbatim, not 0-terminated:
@@ -870,7 +947,7 @@ TEST_F(TraceContentTest, Escaping)
/** Test how the system handles non-UTF8 characters, a violation of its API */
TEST_F(TraceContentTest, NonUtf8)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, true, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, true, false, -1, 1, ULONG_MAX,
all_features));
/*
A string which starts with invalid utf8 (the four first bytes are éèÄà in
@@ -906,8 +983,8 @@ TEST_F(TraceContentTest, NonUtf8)
"}";
EXPECT_STREQ(expected, info.trace_ptr);
EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
- check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
EXPECT_EQ(sizeof(all_chars), info.query_length);
// we get the query unescaped, verbatim, not 0-terminated:
@@ -924,7 +1001,7 @@ TEST_F(TraceContentTest, NonUtf8)
*/
TEST_F(TraceContentTest, Indent)
{
- ASSERT_EQ(false, trace.start(YES_FOR_THIS, false, false, -1, 1, ULONG_MAX,
+ ASSERT_EQ(false, trace.start(true, false, false, false, -1, 1, ULONG_MAX,
all_features));
{
Opt_trace_object oto(&trace);
@@ -966,11 +1043,182 @@ TEST_F(TraceContentTest, Indent)
EXPECT_EQ(20300U, spaces);
check_json_compliance(info.trace_ptr, info.trace_length);
EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
+ EXPECT_FALSE(oom);
+ it.next();
+ ASSERT_TRUE(it.at_end());
+}
+
+
+/** Test Opt_trace_context::missing_privilege() */
+TEST_F(TraceContentTest, MissingPrivilege)
+{
+ ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto(&trace);
+ {
+ Opt_trace_array ota(&trace, "one array");
+ ota.add(200.4);
+ {
+ Opt_trace_object oto1(&trace);
+ oto1.add_alnum("one key", "one value").
+ add("another key", 100LL);
+ oto1.add("a third key", false);
+ Opt_trace_object oto2(&trace, "a fourth key");
+ oto2.add("key inside", 1LL);
+ ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto3(&trace);
+ trace.missing_privilege();
+ ASSERT_FALSE(trace.start(true, false, true, false, 0, 100,
+ ULONG_MAX, all_features));
+ {
+ Opt_trace_object oto4(&trace);
+ oto4.add_alnum("in4","key4");
+ }
+ trace.end();
+ }
+ trace.end(); // this should restore I_S support
+ // so this should be visible
+ oto2.add("another key inside", 5LL);
+ // and this new sub statement too:
+ ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto5(&trace);
+ oto5.add("in5", true);
+ }
+ trace.end();
+ }
+ ota.add_alnum("one string element");
+ ota.add(true);
+ }
+ oto.add("yet another key", -1000LL);
+ {
+ Opt_trace_array ota(&trace, "another array");
+ ota.add(1LL).add(2LL).add(3LL).add(4LL);
+ }
+ }
+ trace.end();
+ Opt_trace_iterator it(&trace);
+ ASSERT_FALSE(it.at_end());
+ Opt_trace_info info;
+ it.get_value(&info);
+ const char expected[]=
+ "{\n"
+ " \"one array\": [\n"
+ " 200.4,\n"
+ " {\n"
+ " \"one key\": \"one value\",\n"
+ " \"another key\": 100,\n"
+ " \"a third key\": false,\n"
+ " \"a fourth key\": {\n"
+ " \"key inside\": 1,\n"
+ " \"another key inside\": 5\n"
+ " } /* a fourth key */\n"
+ " },\n"
+ " \"one string element\",\n"
+ " true\n"
+ " ] /* one array */,\n"
+ " \"yet another key\": -1000,\n"
+ " \"another array\": [\n"
+ " 1,\n"
+ " 2,\n"
+ " 3,\n"
+ " 4\n"
+ " ] /* another array */\n"
+ "}";
+ EXPECT_STREQ(expected, info.trace_ptr);
+ EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
+ check_json_compliance(info.trace_ptr, info.trace_length);
+ EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
EXPECT_FALSE(oom);
it.next();
+ ASSERT_FALSE(it.at_end());
+ // Now the substatement with a missing privilege
+ it.get_value(&info);
+ const char expected2[]= ""; // because of missing privilege...
+ EXPECT_STREQ(expected2, info.trace_ptr);
+ EXPECT_EQ(sizeof(expected2) - 1, info.trace_length);
+ EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_TRUE(info.missing_priv); // ... tested here.
+ it.next();
+ ASSERT_FALSE(it.at_end());
+ // And now the last substatement, visible
+ it.get_value(&info);
+ const char expected3[]=
+ "{\n"
+ " \"in5\": true\n"
+ "}";
+ EXPECT_STREQ(expected3, info.trace_ptr);
+ EXPECT_EQ(sizeof(expected3) - 1, info.trace_length);
+ check_json_compliance(info.trace_ptr, info.trace_length);
+ EXPECT_EQ(0U, info.missing_bytes);
+ EXPECT_FALSE(info.missing_priv);
+ it.next();
+ ASSERT_TRUE(it.at_end());
+}
+
+
+/** Test Opt_trace_context::missing_privilege() on absent trace */
+TEST_F(TraceContentTest, MissingPrivilege2)
+{
+ /*
+ Ask for neither I_S not debug output, and no
+ missing_privilege() support
+ */
+ ASSERT_FALSE(trace.start(false, false, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ EXPECT_FALSE(trace.is_started());
+ trace.end();
+ /*
+ Ask for neither I_S not debug output, but ask that
+ missing_privilege() is supported.
+ */
+ ASSERT_FALSE(trace.start(false, true, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ EXPECT_TRUE(trace.is_started());
+ trace.missing_privilege();
+ // This above should make the substatement below not be traced:
+ ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
+ all_features));
+ {
+ Opt_trace_object oto5(&trace);
+ oto5.add("in5", true);
+ }
+ trace.end();
+ trace.end();
+ Opt_trace_iterator it(&trace);
ASSERT_TRUE(it.at_end());
}
+
+/**
+ Test an optimization: that no Opt_trace_stmt is created in common case
+ where all statements and substatements ask neither for I_S nor for DBUG,
+ nor for support of missing_privilege() function.
+*/
+TEST_F(TraceContentTest, NoOptTraceStmt)
+{
+ ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
+ all_features));
+ EXPECT_FALSE(trace.is_started());
+ // one substatement:
+ ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
+ all_features));
+ EXPECT_FALSE(trace.is_started());
+ // another one deeper nested:
+ ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
+ all_features));
+ EXPECT_FALSE(trace.is_started());
+ trace.end();
+ trace.end();
+ trace.end();
+}
+
} // namespace
#endif // OPTIMIZER_TRACE
Attachment: [text/bzr-bundle] bzr/guilhem.bichot@oracle.com-20110504205328-nh1fn0ujq4y6k9zw.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (guilhem.bichot:3296) | Guilhem Bichot | 4 May |