mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 12:56:14 +01:00 
			
		
		
		
	- 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
 |