mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
a24d0926b9
- Move testing of my_writer to inline functions to avoid calls - Made more functions inline. Especially thd->thread_started() is now very optimized! - Moved Opt_trace_stmt classe to opt_trace_context.h to get critical functions inline
210 lines
8.1 KiB
C++
210 lines
8.1 KiB
C++
#ifndef OPT_TRACE_INCLUDED
|
|
#define OPT_TRACE_INCLUDED
|
|
/* This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "opt_trace_context.h" // Opt_trace_context
|
|
#include "sql_lex.h"
|
|
#include "my_json_writer.h"
|
|
#include "sql_select.h"
|
|
class Item;
|
|
class THD;
|
|
struct TABLE_LIST;
|
|
|
|
/*
|
|
User-visible information about a trace.
|
|
*/
|
|
|
|
struct Opt_trace_info
|
|
{
|
|
/**
|
|
String containing trace.
|
|
If trace has been end()ed, this is 0-terminated, which is only to aid
|
|
debugging or unit testing; this property is not relied upon in normal
|
|
server usage.
|
|
If trace has not been ended, this is not 0-terminated. That rare case can
|
|
happen when a substatement reads OPTIMIZER_TRACE (at that stage, the top
|
|
statement is still executing so its trace is not ended yet, but may still
|
|
be read by the sub-statement).
|
|
*/
|
|
const char *trace_ptr;
|
|
size_t trace_length;
|
|
//// String containing original query.
|
|
const char *query_ptr;
|
|
size_t query_length;
|
|
const CHARSET_INFO *query_charset; ///< charset of query string
|
|
/**
|
|
How many bytes this trace is missing (for traces which were truncated
|
|
because of @@@@optimizer-trace-max-mem-size).
|
|
The trace is not extended beyond trace-max-mem-size.
|
|
*/
|
|
size_t missing_bytes;
|
|
/*
|
|
Whether user lacks privilege to see this trace.
|
|
If this is set to TRUE, then we return an empty trace
|
|
*/
|
|
bool missing_priv;
|
|
};
|
|
|
|
/**
|
|
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.
|
|
|
|
@param thd the THD
|
|
@param tbl list of tables read/written by the statement.
|
|
@param sql_command SQL command being prepared or executed
|
|
@param set_vars what variables are set by this command (only used if
|
|
sql_command is SQLCOM_SET_OPTION)
|
|
@param query query
|
|
@param length query's length
|
|
@param charset charset which was used to encode this query
|
|
*/
|
|
|
|
|
|
class Opt_trace_start {
|
|
public:
|
|
Opt_trace_start(THD *thd_arg, TABLE_LIST *tbl,
|
|
enum enum_sql_command sql_command,
|
|
List<set_var_base> *set_vars,
|
|
const char *query,
|
|
size_t query_length,
|
|
const CHARSET_INFO *query_charset);
|
|
~Opt_trace_start();
|
|
|
|
private:
|
|
Opt_trace_context *const ctx;
|
|
/*
|
|
True: the query will be traced
|
|
False: otherwise
|
|
*/
|
|
bool traceable;
|
|
};
|
|
|
|
/**
|
|
Prints SELECT query to optimizer trace. It is not the original query (as in
|
|
@c 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
|
|
@param trace_object Json_writer object to which the query will be added
|
|
*/
|
|
void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
|
|
Json_writer_object *trace_object);
|
|
|
|
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab);
|
|
void trace_plan_prefix(JOIN *join, uint idx, table_map join_tables);
|
|
void print_final_join_order(JOIN *join);
|
|
void print_best_access_for_table(THD *thd, POSITION *pos,
|
|
enum join_type type);
|
|
|
|
/*
|
|
Security related (need to add a proper comment here)
|
|
*/
|
|
|
|
/**
|
|
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.
|
|
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);
|
|
|
|
void opt_trace_disable_if_no_tables_access(THD *thd, TABLE_LIST *tbl);
|
|
|
|
/**
|
|
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);
|
|
|
|
/**
|
|
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);
|
|
|
|
/**
|
|
Fills information_schema.OPTIMIZER_TRACE with rows (one per trace)
|
|
@retval 0 ok
|
|
@retval 1 error
|
|
*/
|
|
int fill_optimizer_trace_info(THD *thd, TABLE_LIST *tables, Item *);
|
|
|
|
#define OPT_TRACE_TRANSFORM(thd, object_level0, object_level1, \
|
|
select_number, from, to) \
|
|
Json_writer_object object_level0(thd); \
|
|
Json_writer_object object_level1(thd, "transformation"); \
|
|
object_level1.add_select_number(select_number).add("from", from).add("to", to);
|
|
|
|
#define OPT_TRACE_VIEWS_TRANSFORM(thd, object_level0, object_level1, \
|
|
derived, name, select_number, algorithm) \
|
|
Json_writer_object trace_wrapper(thd); \
|
|
Json_writer_object trace_derived(thd, derived); \
|
|
trace_derived.add("table", name).add_select_number(select_number) \
|
|
.add("algorithm", algorithm);
|
|
#endif
|