mariadb/sql/set_var.h
Alexander Barkov fd247cc21f MDEV-31340 Remove MY_COLLATION_HANDLER::strcasecmp()
This patch also fixes:
  MDEV-33050 Build-in schemas like oracle_schema are accent insensitive
  MDEV-33084 LASTVAL(t1) and LASTVAL(T1) do not work well with lower-case-table-names=0
  MDEV-33085 Tables T1 and t1 do not work well with ENGINE=CSV and lower-case-table-names=0
  MDEV-33086 SHOW OPEN TABLES IN DB1 -- is case insensitive with lower-case-table-names=0
  MDEV-33088 Cannot create triggers in the database `MYSQL`
  MDEV-33103 LOCK TABLE t1 AS t2 -- alias is not case sensitive with lower-case-table-names=0
  MDEV-33109 DROP DATABASE MYSQL -- does not drop SP with lower-case-table-names=0
  MDEV-33110 HANDLER commands are case insensitive with lower-case-table-names=0
  MDEV-33119 User is case insensitive in INFORMATION_SCHEMA.VIEWS
  MDEV-33120 System log table names are case insensitive with lower-cast-table-names=0

- Removing the virtual function strnncoll() from MY_COLLATION_HANDLER

- Adding a wrapper function CHARSET_INFO::streq(), to compare
  two strings for equality. For now it calls strnncoll() internally.
  In the future it will turn into a virtual function.

- Adding new accent sensitive case insensitive collations:
    - utf8mb4_general1400_as_ci
    - utf8mb3_general1400_as_ci
  They implement accent sensitive case insensitive comparison.
  The weight of a character is equal to the code point of its
  upper case variant. These collations use Unicode-14.0.0 casefolding data.

  The result of
     my_charset_utf8mb3_general1400_as_ci.strcoll()
  is very close to the former
     my_charset_utf8mb3_general_ci.strcasecmp()

  There is only a difference in a couple dozen rare characters, because:
    - the switch from "tolower" to "toupper" comparison, to make
      utf8mb3_general1400_as_ci closer to utf8mb3_general_ci
    - the switch from Unicode-3.0.0 to Unicode-14.0.0
  This difference should be tolarable. See the list of affected
  characters in the MDEV description.

  Note, utf8mb4_general1400_as_ci correctly handles non-BMP characters!
  Unlike utf8mb4_general_ci, it does not treat all BMP characters
  as equal.

- Adding classes representing names of the file based database objects:

    Lex_ident_db
    Lex_ident_table
    Lex_ident_trigger

  Their comparison collation depends on the underlying
  file system case sensitivity and on --lower-case-table-names
  and can be either my_charset_bin or my_charset_utf8mb3_general1400_as_ci.

- Adding classes representing names of other database objects,
  whose names have case insensitive comparison style,
  using my_charset_utf8mb3_general1400_as_ci:

  Lex_ident_column
  Lex_ident_sys_var
  Lex_ident_user_var
  Lex_ident_sp_var
  Lex_ident_ps
  Lex_ident_i_s_table
  Lex_ident_window
  Lex_ident_func
  Lex_ident_partition
  Lex_ident_with_element
  Lex_ident_rpl_filter
  Lex_ident_master_info
  Lex_ident_host
  Lex_ident_locale
  Lex_ident_plugin
  Lex_ident_engine
  Lex_ident_server
  Lex_ident_savepoint
  Lex_ident_charset
  engine_option_value::Name

- All the mentioned Lex_ident_xxx classes implement a method streq():

  if (ident1.streq(ident2))
     do_equal();

  This method works as a wrapper for CHARSET_INFO::streq().

- Changing a lot of "LEX_CSTRING name" to "Lex_ident_xxx name"
  in class members and in function/method parameters.

- Replacing all calls like
    system_charset_info->coll->strcasecmp(ident1, ident2)
  to
    ident1.streq(ident2)

- Taking advantage of the c++11 user defined literal operator
  for LEX_CSTRING (see m_strings.h) and Lex_ident_xxx (see lex_ident.h)
  data types. Use example:

  const Lex_ident_column primary_key_name= "PRIMARY"_Lex_ident_column;

  is now a shorter version of:

  const Lex_ident_column primary_key_name=
    Lex_ident_column({STRING_WITH_LEN("PRIMARY")});
2024-04-18 15:22:10 +04:00

493 lines
16 KiB
C++

#ifndef SET_VAR_INCLUDED
#define SET_VAR_INCLUDED
/* Copyright (c) 2002, 2013, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB
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 Street, Fifth Floor, Boston, MA 02110-1335 USA */
/**
@file
"public" interface to sys_var - server configuration variables.
*/
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
#include <my_getopt.h>
class sys_var;
class set_var;
class sys_var_pluginvar;
class PolyLock;
class Item_func_set_user_var;
// This include needs to be here since item.h requires enum_var_type :-P
#include "item.h" /* Item */
#include "sql_class.h" /* THD */
extern TYPELIB bool_typelib;
struct sys_var_chain
{
sys_var *first;
sys_var *last;
};
int mysql_add_sys_var_chain(sys_var *chain);
int mysql_del_sys_var_chain(sys_var *chain);
/**
A class representing one system variable - that is something
that can be accessed as @@global.variable_name or @@session.variable_name,
visible in SHOW xxx VARIABLES and in INFORMATION_SCHEMA.xxx_VARIABLES,
optionally it can be assigned to, optionally it can have a command-line
counterpart with the same name.
*/
class sys_var: protected Value_source // for double_from_string_with_check
{
public:
sys_var *next;
LEX_CSTRING name;
bool *test_load;
enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023,
READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096,
NO_SET_STATEMENT=8192, AUTO_SET=16384};
enum { NO_GETOPT=-1, GETOPT_ONLY_HELP=-2 };
enum where { CONFIG, COMMAND_LINE, AUTO, SQL, COMPILE_TIME, ENV };
/**
Enumeration type to indicate for a system variable whether
it will be written to the binlog or not.
*/
enum binlog_status_enum { VARIABLE_NOT_IN_BINLOG,
SESSION_VARIABLE_IN_BINLOG } binlog_status;
my_option option; ///< min, max, default values are stored here
enum where value_origin;
const char *origin_filename;
protected:
typedef bool (*on_check_function)(sys_var *self, THD *thd, set_var *var);
typedef bool (*on_update_function)(sys_var *self, THD *thd, enum_var_type type);
int flags; ///< or'ed flag_enum values
SHOW_TYPE show_val_type; ///< what value_ptr() returns for sql_show.cc
PolyLock *guard; ///< *second* lock that protects the variable
ptrdiff_t offset; ///< offset to the value from global_system_variables
on_check_function on_check;
on_update_function on_update;
const char *const deprecation_substitute;
public:
sys_var(sys_var_chain *chain, const char *name_arg, const char *comment,
int flag_args, ptrdiff_t off, int getopt_id,
enum get_opt_arg_type getopt_arg_type, SHOW_TYPE show_val_type_arg,
longlong def_val, PolyLock *lock, enum binlog_status_enum binlog_status_arg,
on_check_function on_check_func, on_update_function on_update_func,
const char *substitute);
virtual ~sys_var() = default;
/**
All the cleanup procedures should be performed here
*/
virtual void cleanup() {}
/**
downcast for sys_var_pluginvar. Returns this if it's an instance
of sys_var_pluginvar, and 0 otherwise.
*/
virtual sys_var_pluginvar *cast_pluginvar() { return 0; }
bool check(THD *thd, set_var *var);
const uchar *value_ptr(THD *thd, enum_var_type type, const LEX_CSTRING *base) const;
/**
Update the system variable with the default value from either
session or global scope. The default value is stored in the
'var' argument. Return false when successful.
*/
bool set_default(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
String *val_str_nolock(String *str, THD *thd, const uchar *value);
longlong val_int(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base);
String *val_str(String *str, THD *thd, enum_var_type type, const LEX_CSTRING *base);
double val_real(bool *is_null, THD *thd, enum_var_type type, const LEX_CSTRING *base);
SHOW_TYPE show_type() const { return show_val_type; }
int scope() const { return flags & SCOPE_MASK; }
virtual CHARSET_INFO *charset(THD *thd) const
{
return system_charset_info_for_i_s;
}
bool is_readonly() const { return flags & READONLY; }
void update_flags(int new_flags) { flags = new_flags; }
int get_flags() const { return flags; }
/**
the following is only true for keycache variables,
that support the syntax @@keycache_name.variable_name
*/
bool is_struct() { return option.var_type & GET_ASK_ADDR; }
bool is_set_stmt_ok() const { return !(flags & NO_SET_STATEMENT); }
bool is_written_to_binlog(enum_var_type type)
{ return type != OPT_GLOBAL && binlog_status == SESSION_VARIABLE_IN_BINLOG; }
bool check_update_type(const Item *item)
{
Item_result type= item->result_type();
switch (option.var_type & GET_TYPE_MASK) {
case GET_INT:
case GET_UINT:
case GET_LONG:
case GET_ULONG:
case GET_LL:
case GET_ULL:
return type != INT_RESULT &&
(type != DECIMAL_RESULT || item->decimals != 0);
case GET_STR:
case GET_STR_ALLOC:
return type != STRING_RESULT;
case GET_ENUM:
case GET_BOOL:
case GET_SET:
case GET_FLAGSET:
case GET_BIT:
return type != STRING_RESULT && type != INT_RESULT;
case GET_DOUBLE:
return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
default:
return true;
}
}
bool check_type(enum_var_type type)
{
switch (scope())
{
case GLOBAL: return type != OPT_GLOBAL;
case SESSION: return false; // always ok
case ONLY_SESSION: return type == OPT_GLOBAL;
}
return true; // keep gcc happy
}
bool register_option(DYNAMIC_ARRAY *array, int parse_flags)
{
DBUG_ASSERT(parse_flags == GETOPT_ONLY_HELP ||
parse_flags == PARSE_EARLY || parse_flags == 0);
if (option.id == NO_GETOPT)
return 0;
if (parse_flags == GETOPT_ONLY_HELP)
{
if (option.id != GETOPT_ONLY_HELP)
return 0;
}
else
{
if (option.id == GETOPT_ONLY_HELP)
return 0;
if ((flags & PARSE_EARLY) != parse_flags)
return 0;
}
return insert_dynamic(array, (uchar*)&option);
}
void do_deprecated_warning(THD *thd);
/**
whether session value of a sysvar is a default one.
in this simple implementation we don't distinguish between default
and non-default values. for most variables it's ok, they don't treat
default values specially. this method is overwritten in descendant
classes as necessary.
*/
virtual bool session_is_default(THD *thd) { return false; }
virtual const uchar *default_value_ptr(THD *thd) const
{ return (uchar*)&option.def_value; }
virtual bool on_check_access_global(THD *thd) const;
virtual bool on_check_access_session(THD *thd) const
{
return false;
}
private:
virtual bool do_check(THD *thd, set_var *var) = 0;
/**
save the session default value of the variable in var
*/
virtual void session_save_default(THD *thd, set_var *var) = 0;
/**
save the global default value of the variable in var
*/
virtual void global_save_default(THD *thd, set_var *var) = 0;
virtual bool session_update(THD *thd, set_var *var) = 0;
virtual bool global_update(THD *thd, set_var *var) = 0;
protected:
/**
A pointer to a value of the variable for SHOW.
It must be of show_val_type type (my_bool for SHOW_MY_BOOL,
int for SHOW_INT, longlong for SHOW_LONGLONG, etc).
*/
virtual const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const;
virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
/**
A pointer to a storage area of the variable, to the raw data.
Typically it's the same as session_value_ptr(), but it's different,
for example, for ENUM, that is printed as a string, but stored as a number.
*/
uchar *session_var_ptr(THD *thd) const
{ return ((uchar*)&(thd->variables)) + offset; }
uchar *global_var_ptr() const
{ return ((uchar*)&global_system_variables) + offset; }
void *max_var_ptr()
{
return scope() == SESSION ? (((uchar*)&max_system_variables) + offset) :
0;
}
friend class Session_sysvars_tracker;
friend class Session_tracker;
};
#include "sql_plugin.h" /* SHOW_HA_ROWS, SHOW_MY_BOOL */
/****************************************************************************
Classes for parsing of the SET command
****************************************************************************/
/**
A base class for everything that can be set with SET command.
It's similar to Items, an instance of this is created by the parser
for every assigmnent in SET (or elsewhere, e.g. in SELECT).
*/
class set_var_base :public Sql_alloc
{
public:
set_var_base() = default;
virtual ~set_var_base() = default;
virtual int check(THD *thd)=0; /* To check privileges etc. */
virtual int update(THD *thd)=0; /* To set the value */
virtual int light_check(THD *thd) { return check(thd); } /* for PS */
virtual bool is_system() { return FALSE; }
/**
@returns whether this variable is @@@@optimizer_trace.
*/
virtual bool is_var_optimizer_trace() const { return false; }
};
/**
Structure for holding unix timestamp and high precision second part.
*/
typedef struct my_time_t_hires
{
my_time_t unix_time;
ulong second_part;
} my_time_t_hires;
/**
set_var_base descendant for assignments to the system variables.
*/
class set_var :public set_var_base
{
public:
sys_var *var; ///< system variable to be updated
Item *value; ///< the expression that provides the new value of the variable
enum_var_type type;
union ///< temp storage to hold a value between sys_var::check and ::update
{
ulonglong ulonglong_value; ///< for unsigned integer, set, enum sysvars
longlong longlong_value; ///< for signed integer
double double_value; ///< for Sys_var_double
plugin_ref plugin; ///< for Sys_var_plugin
plugin_ref *plugins; ///< for Sys_var_pluginlist
Time_zone *time_zone; ///< for Sys_var_tz
LEX_STRING string_value; ///< for Sys_var_charptr and others
my_time_t_hires timestamp; ///< for Sys_var_vers_asof
const void *ptr; ///< for Sys_var_struct
} save_result;
LEX_CSTRING base; /**< for structured variables, like keycache_name.variable_name */
set_var(THD *thd, enum_var_type type_arg, sys_var *var_arg,
const LEX_CSTRING *base_name_arg, Item *value_arg);
virtual bool is_system() { return 1; }
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
virtual bool is_var_optimizer_trace() const
{
extern sys_var *Sys_optimizer_trace_ptr;
return var == Sys_optimizer_trace_ptr;
}
};
/* User variables like @my_own_variable */
class set_var_user: public set_var_base
{
Item_func_set_user_var *user_var_item;
public:
set_var_user(Item_func_set_user_var *item)
:user_var_item(item)
{}
int check(THD *thd);
int update(THD *thd);
int light_check(THD *thd);
};
/* For SET PASSWORD */
class set_var_password: public set_var_base
{
LEX_USER *user;
public:
set_var_password(LEX_USER *user_arg) :user(user_arg)
{}
int check(THD *thd);
int update(THD *thd);
};
/* For SET ROLE */
class set_var_role: public set_var_base
{
LEX_CSTRING role;
privilege_t access;
public:
set_var_role(LEX_CSTRING role_arg) : role(role_arg), access(NO_ACL) {}
int check(THD *thd);
int update(THD *thd);
};
/* For SET DEFAULT ROLE */
class set_var_default_role: public set_var_base
{
LEX_USER *user, *real_user;
LEX_CSTRING role;
LEX_CSTRING real_role;
public:
set_var_default_role(LEX_USER *user_arg, LEX_CSTRING role_arg) :
user(user_arg), role(role_arg) {}
int check(THD *thd);
int update(THD *thd);
};
/* For SET NAMES and SET CHARACTER SET */
class set_var_collation_client: public set_var_base
{
CHARSET_INFO *character_set_client;
CHARSET_INFO *character_set_results;
CHARSET_INFO *collation_connection;
public:
set_var_collation_client(CHARSET_INFO *client_coll_arg,
CHARSET_INFO *connection_coll_arg,
CHARSET_INFO *result_coll_arg)
:character_set_client(client_coll_arg),
character_set_results(result_coll_arg),
collation_connection(connection_coll_arg)
{}
int check(THD *thd);
int update(THD *thd);
};
/* optional things, have_* variables */
extern SHOW_COMP_OPTION have_csv, have_innodb;
extern SHOW_COMP_OPTION have_ndbcluster, have_partitioning;
extern SHOW_COMP_OPTION have_profiling;
extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
extern SHOW_COMP_OPTION have_query_cache;
extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
extern SHOW_COMP_OPTION have_crypt;
extern SHOW_COMP_OPTION have_compress;
extern SHOW_COMP_OPTION have_openssl;
/*
Prototypes for helper functions
*/
ulong get_system_variable_hash_records(void);
ulonglong get_system_variable_hash_version(void);
SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type);
int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond);
sys_var *find_sys_var(THD *thd, const char *str, size_t length= 0,
bool throw_error= false);
int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free);
#define SYSVAR_AUTOSIZE(VAR,VAL) \
do { \
VAR= (VAL); \
set_sys_var_value_origin(&VAR, sys_var::AUTO); \
} while(0)
#define SYSVAR_AUTOSIZE_IF_CHANGED(VAR,VAL,TYPE) \
do { \
TYPE tmp= (VAL); \
if (VAR != tmp) \
{ \
VAR= (VAL); \
set_sys_var_value_origin(&VAR, sys_var::AUTO); \
} \
} while(0)
void set_sys_var_value_origin(void *ptr, enum sys_var::where here,
const char *filename= NULL);
enum sys_var::where get_sys_var_value_origin(void *ptr);
inline bool IS_SYSVAR_AUTOSIZE(void *ptr)
{
enum sys_var::where res= get_sys_var_value_origin(ptr);
return (res == sys_var::AUTO || res == sys_var::COMPILE_TIME);
}
bool fix_delay_key_write(sys_var *self, THD *thd, enum_var_type type);
sql_mode_t expand_sql_mode(sql_mode_t sql_mode);
#ifndef EMBEDDED_LIBRARY
bool validate_redirect_url(char *str, size_t len);
#endif
const char *sql_mode_string_representation(uint bit_number);
bool sql_mode_string_representation(THD *thd, sql_mode_t sql_mode,
LEX_CSTRING *ls);
int default_regex_flags_pcre(THD *thd);
extern sys_var *Sys_autocommit_ptr, *Sys_last_gtid_ptr,
*Sys_character_set_client_ptr, *Sys_character_set_connection_ptr,
*Sys_character_set_results_ptr;
CHARSET_INFO *get_old_charset_by_name(const LEX_CSTRING &name);
int sys_var_init();
uint sys_var_elements();
int sys_var_add_options(DYNAMIC_ARRAY *long_options, int parse_flags);
void sys_var_end(void);
bool check_has_super(sys_var *self, THD *thd, set_var *var);
plugin_ref *resolve_engine_list(THD *thd, const char *str_arg, size_t str_arg_len,
bool error_on_unknown_engine, bool temp_copy);
void free_engine_list(plugin_ref *list);
plugin_ref *copy_engine_list(plugin_ref *list);
plugin_ref *temp_copy_engine_list(THD *thd, plugin_ref *list);
char *pretty_print_engine_list(THD *thd, plugin_ref *list);
#endif