mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	 fd247cc21f
			
		
	
	
	fd247cc21f
	
	
	
		
			
			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")});
		
	
			
		
			
				
	
	
		
			318 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|   Copyright (c) 2008, Roland Bouman
 | |
|   http://rpbouman.blogspot.com/
 | |
|   roland.bouman@gmail.com
 | |
|   All rights reserved.
 | |
| 
 | |
|   Redistribution and use in source and binary forms, with or without
 | |
|   modification, are permitted provided that the following conditions are met:
 | |
|       * Redistributions of source code must retain the above copyright
 | |
|         notice, this list of conditions and the following disclaimer.
 | |
|       * Redistributions in binary form must reproduce the above copyright
 | |
|         notice, this list of conditions and the following disclaimer in the
 | |
|         documentation and/or other materials provided with the distribution.
 | |
|       * Neither the name of the Roland Bouman nor the
 | |
|         names of the contributors may be used to endorse or promote products
 | |
|         derived from this software without specific prior written permission.
 | |
| 
 | |
|   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | |
|   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | |
|   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | |
|   DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 | |
|   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | |
|   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | |
|   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | |
|   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | |
|   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #ifndef MYSQL_SERVER
 | |
| #define MYSQL_SERVER
 | |
| #endif
 | |
| 
 | |
| #include <my_global.h>
 | |
| #include <sql_parse.h>          // check_global_access
 | |
| #include <sql_acl.h>            // PROCESS_ACL
 | |
| #include <sql_class.h>          // THD
 | |
| #include <sql_cache.h>
 | |
| #include <sql_i_s.h>            // ST_SCHEMA_TABLE
 | |
| #include <set_var.h>            // sql_mode_string_representation
 | |
| #include <tztime.h>
 | |
| #include <mysql/plugin.h>
 | |
| 
 | |
| class Accessible_Query_Cache : public Query_cache {
 | |
| public:
 | |
|   HASH *get_queries()
 | |
|   {
 | |
|     return &this->queries;
 | |
|   }
 | |
| } *qc;
 | |
| 
 | |
| bool schema_table_store_record(THD *thd, TABLE *table);
 | |
| 
 | |
| #define MAX_STATEMENT_TEXT_LENGTH 32767
 | |
| #define COLUMN_STATEMENT_SCHEMA 0
 | |
| #define COLUMN_STATEMENT_TEXT 1
 | |
| #define COLUMN_RESULT_BLOCKS_COUNT 2
 | |
| #define COLUMN_RESULT_BLOCKS_SIZE 3
 | |
| #define COLUMN_RESULT_BLOCKS_SIZE_USED 4
 | |
| #define COLUMN_LIMIT 5
 | |
| #define COLUMN_MAX_SORT_LENGTH 6
 | |
| #define COLUMN_GROUP_CONCAT_MAX_LENGTH 7
 | |
| #define COLUMN_CHARACTER_SET_CLIENT 8
 | |
| #define COLUMN_CHARACTER_SET_RESULT 9
 | |
| #define COLUMN_COLLATION 10
 | |
| #define COLUMN_TIMEZONE 11
 | |
| #define COLUMN_DEFAULT_WEEK_FORMAT 12
 | |
| #define COLUMN_DIV_PRECISION_INCREMENT 13
 | |
| #define COLUMN_SQL_MODE 14
 | |
| #define COLUMN_LC_TIME_NAMES 15
 | |
| 
 | |
| #define COLUMN_CLIENT_LONG_FLAG 16
 | |
| #define COLUMN_CLIENT_PROTOCOL_41 17
 | |
| #define COLUMN_CLIENT_EXTENDED_METADATA 18
 | |
| #define COLUMN_PROTOCOL_TYPE 19
 | |
| #define COLUMN_MORE_RESULTS_EXISTS 20
 | |
| #define COLUMN_IN_TRANS 21
 | |
| #define COLUMN_AUTOCOMMIT 22
 | |
| #define COLUMN_PKT_NR 23
 | |
| #define COLUMN_HITS 24
 | |
| 
 | |
| 
 | |
| namespace Show {
 | |
| 
 | |
| /* ST_FIELD_INFO is defined in table.h */
 | |
| static ST_FIELD_INFO qc_info_fields[]=
 | |
| {
 | |
|   Column("STATEMENT_SCHEMA",      Varchar(NAME_LEN),                  NOT_NULL),
 | |
|   Column("STATEMENT_TEXT",        Longtext(MAX_STATEMENT_TEXT_LENGTH),NOT_NULL),
 | |
|   Column("RESULT_BLOCKS_COUNT",   SLong(),                            NOT_NULL),
 | |
|   Column("RESULT_BLOCKS_SIZE",    SLonglong(MY_INT32_NUM_DECIMAL_DIGITS),NOT_NULL),
 | |
|   Column("RESULT_BLOCKS_SIZE_USED",SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("LIMIT",                 SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("MAX_SORT_LENGTH",       SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("GROUP_CONCAT_MAX_LENGTH",SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("CHARACTER_SET_CLIENT",  CSName(),                           NOT_NULL),
 | |
|   Column("CHARACTER_SET_RESULT",  CSName(),                           NOT_NULL),
 | |
|   Column("COLLATION",             CLName(),                           NOT_NULL),
 | |
|   Column("TIMEZONE",              Varchar(50),                        NOT_NULL),
 | |
|   Column("DEFAULT_WEEK_FORMAT",   SLong(),                            NOT_NULL),
 | |
|   Column("DIV_PRECISION_INCREMENT",SLong(),                           NOT_NULL),
 | |
|   Column("SQL_MODE",              Varchar(250),                       NOT_NULL),
 | |
|   Column("LC_TIME_NAMES",         Varchar(100),                       NOT_NULL),
 | |
|   Column("CLIENT_LONG_FLAG",      STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("CLIENT_PROTOCOL_41",    STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("CLIENT_EXTENDED_METADATA",STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("PROTOCOL_TYPE",         STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("MORE_RESULTS_EXISTS",   STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("IN_TRANS",              STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("AUTOCOMMIT",            STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("PACKET_NUMBER",         STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   Column("HITS",              SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
 | |
|   CEnd()
 | |
| };
 | |
| 
 | |
| } // namespace Show
 | |
| 
 | |
| 
 | |
| static const char unknown[]= "#UNKNOWN#";
 | |
| 
 | |
| static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
 | |
|                                               COND *cond)
 | |
| {
 | |
|   int status= 1;
 | |
|   CHARSET_INFO *scs= system_charset_info;
 | |
|   TABLE *table= tables->table;
 | |
|   HASH *queries = qc->get_queries();
 | |
| 
 | |
|   /* one must have PROCESS privilege to see others' queries */
 | |
|   if (check_global_access(thd, PROCESS_ACL, true))
 | |
|     return 0;
 | |
| 
 | |
|   if (qc->try_lock(thd))
 | |
|     return 0; // QC is or is being disabled
 | |
| 
 | |
|   /* loop through all queries in the query cache */
 | |
|   for (uint i= 0; i < queries->records; i++)
 | |
|   {
 | |
|     const uchar *query_cache_block_raw;
 | |
|     Query_cache_block* query_cache_block;
 | |
|     Query_cache_query* query_cache_query;
 | |
|     Query_cache_query_flags flags;
 | |
|     uint result_blocks_count;
 | |
|     ulonglong result_blocks_size;
 | |
|     ulonglong result_blocks_size_used;
 | |
|     Query_cache_block *first_result_block;
 | |
|     Query_cache_block *result_block;
 | |
|     const char *statement_text;
 | |
|     size_t statement_text_length;
 | |
|     size_t flags_length;
 | |
|     const char *key, *db;
 | |
|     size_t key_length, db_length;
 | |
|     LEX_CSTRING sql_mode_str;
 | |
|     const String *tz;
 | |
|     CHARSET_INFO *cs_client;
 | |
|     CHARSET_INFO *cs_result;
 | |
|     CHARSET_INFO *collation;
 | |
| 
 | |
|     query_cache_block_raw = my_hash_element(queries, i);
 | |
|     query_cache_block = (Query_cache_block*)query_cache_block_raw;
 | |
|     if (unlikely(!query_cache_block ||
 | |
|                  query_cache_block->type != Query_cache_block::QUERY))
 | |
|       continue;
 | |
| 
 | |
|     query_cache_query = query_cache_block->query();
 | |
| 
 | |
|     /* Get the actual SQL statement for this query cache query */
 | |
|     statement_text = (const char*)query_cache_query->query();
 | |
|     statement_text_length = strlen(statement_text);
 | |
|     /* We truncate SQL statements up to MAX_STATEMENT_TEXT_LENGTH in our I_S table */
 | |
|     table->field[COLUMN_STATEMENT_TEXT]->store((char*)statement_text,
 | |
|            MY_MIN(statement_text_length, MAX_STATEMENT_TEXT_LENGTH), scs);
 | |
| 
 | |
|     /* get the entire key that identifies this query cache query */
 | |
|     key = (const char*)query_cache_query_get_key(query_cache_block_raw,
 | |
|                                                  &key_length, 0);
 | |
|     /* get and store the flags */
 | |
|     flags_length= key_length - QUERY_CACHE_FLAGS_SIZE;
 | |
|     memcpy(&flags, key+flags_length, QUERY_CACHE_FLAGS_SIZE);
 | |
|     table->field[COLUMN_LIMIT]->store(flags.limit, 0);
 | |
|     table->field[COLUMN_MAX_SORT_LENGTH]->store(flags.max_sort_length, 0);
 | |
|     table->field[COLUMN_GROUP_CONCAT_MAX_LENGTH]->store(flags.group_concat_max_len, 0);
 | |
| 
 | |
|     cs_client= get_charset(flags.character_set_client_num, MYF(MY_WME));
 | |
|     if (likely(cs_client))
 | |
|       table->field[COLUMN_CHARACTER_SET_CLIENT]->
 | |
|         store(&cs_client->cs_name, scs);
 | |
|     else
 | |
|       table->field[COLUMN_CHARACTER_SET_CLIENT]->
 | |
|         store(STRING_WITH_LEN(unknown), scs);
 | |
| 
 | |
|     cs_result= get_charset(flags.character_set_results_num, MYF(MY_WME));
 | |
|     if (likely(cs_result))
 | |
|       table->field[COLUMN_CHARACTER_SET_RESULT]->store(&cs_result->cs_name, scs);
 | |
|     else
 | |
|       table->field[COLUMN_CHARACTER_SET_RESULT]->
 | |
|         store(STRING_WITH_LEN(unknown), scs);
 | |
| 
 | |
|     collation= get_charset(flags.collation_connection_num, MYF(MY_WME));
 | |
|     if (likely(collation))
 | |
|       table->field[COLUMN_COLLATION]-> store(&collation->coll_name, scs);
 | |
|     else
 | |
|       table->field[COLUMN_COLLATION]-> store(STRING_WITH_LEN(unknown), scs);
 | |
| 
 | |
|     tz= flags.time_zone->get_name();
 | |
|     if (likely(tz))
 | |
|       table->field[COLUMN_TIMEZONE]->store(tz->ptr(), tz->length(), scs);
 | |
|     else
 | |
|       table->field[COLUMN_TIMEZONE]-> store(STRING_WITH_LEN(unknown), scs);
 | |
|     table->field[COLUMN_DEFAULT_WEEK_FORMAT]->store(flags.default_week_format, 0);
 | |
|     table->field[COLUMN_DIV_PRECISION_INCREMENT]->store(flags.div_precision_increment, 0);
 | |
| 
 | |
|     sql_mode_string_representation(thd, flags.sql_mode, &sql_mode_str);
 | |
|     table->field[COLUMN_SQL_MODE]->store(sql_mode_str.str, sql_mode_str.length, scs);
 | |
| 
 | |
|     table->field[COLUMN_LC_TIME_NAMES]->store(flags.lc_time_names->name, scs);
 | |
| 
 | |
|     table->field[COLUMN_CLIENT_LONG_FLAG]->store(flags.client_long_flag, 0);
 | |
|     table->field[COLUMN_CLIENT_PROTOCOL_41]->store(flags.client_protocol_41, 0);
 | |
|     table->field[COLUMN_CLIENT_EXTENDED_METADATA]->
 | |
|       store(flags.client_extended_metadata, 0);
 | |
|     table->field[COLUMN_PROTOCOL_TYPE]->store(flags.protocol_type, 0);
 | |
|     table->field[COLUMN_MORE_RESULTS_EXISTS]->store(flags.more_results_exists, 0);
 | |
|     table->field[COLUMN_IN_TRANS]->store(flags.in_trans, 0);
 | |
|     table->field[COLUMN_AUTOCOMMIT]->store(flags.autocommit, 0);
 | |
|     table->field[COLUMN_PKT_NR]->store(flags.pkt_nr, 0);
 | |
|     table->field[COLUMN_HITS]->store(query_cache_query->hits(), 0);
 | |
| 
 | |
|     /* The database against which the statement is executed is part of the
 | |
|        query cache query key
 | |
|      */
 | |
|     compile_time_assert(QUERY_CACHE_DB_LENGTH_SIZE == 2); 
 | |
|     db= key + statement_text_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE;
 | |
|     db_length= uint2korr(db - QUERY_CACHE_DB_LENGTH_SIZE);
 | |
| 
 | |
|     table->field[COLUMN_STATEMENT_SCHEMA]->store(db, db_length, scs);
 | |
| 
 | |
|     /* If we have result blocks, process them */
 | |
|     first_result_block= query_cache_query->result();
 | |
|     if(query_cache_query->is_results_ready() &&
 | |
|        first_result_block)
 | |
|     {
 | |
|       /* initialize so we can loop over the result blocks*/
 | |
|       result_block= first_result_block;
 | |
|       result_blocks_count = 1;
 | |
|       result_blocks_size = result_block->length;
 | |
|       result_blocks_size_used = result_block->used;
 | |
| 
 | |
|       /* loop over the result blocks*/
 | |
|       while((result_block= result_block->next)!=first_result_block)
 | |
|       {
 | |
|         /* calculate total number of result blocks */
 | |
|         result_blocks_count++;
 | |
|         /* calculate total size of result blocks */
 | |
|         result_blocks_size += result_block->length;
 | |
|         /* calculate total of used size of result blocks */
 | |
|         result_blocks_size_used += result_block->used;
 | |
|       }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       result_blocks_count = 0;
 | |
|       result_blocks_size = 0;
 | |
|       result_blocks_size_used = 0;
 | |
|     }
 | |
|     table->field[COLUMN_RESULT_BLOCKS_COUNT]->store(result_blocks_count, 0);
 | |
|     table->field[COLUMN_RESULT_BLOCKS_SIZE]->store(result_blocks_size, 0);
 | |
|     table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->
 | |
|       store(result_blocks_size_used, 0);
 | |
| 
 | |
|     if (schema_table_store_record(thd, table))
 | |
|       goto cleanup;
 | |
|   }
 | |
|   status = 0;
 | |
| 
 | |
| cleanup:
 | |
|   qc->unlock();
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| static int qc_info_plugin_init(void *p)
 | |
| {
 | |
|   ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
 | |
| 
 | |
|   schema->fields_info= Show::qc_info_fields;
 | |
|   schema->fill_table= qc_info_fill_table;
 | |
|   qc = (Accessible_Query_Cache *)&query_cache;
 | |
| 
 | |
|   return qc == 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static struct st_mysql_information_schema qc_info_plugin=
 | |
| { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
 | |
| 
 | |
| /*
 | |
|   Plugin library descriptor
 | |
| */
 | |
| 
 | |
| maria_declare_plugin(query_cache_info)
 | |
| {
 | |
|   MYSQL_INFORMATION_SCHEMA_PLUGIN,
 | |
|   &qc_info_plugin,
 | |
|   "QUERY_CACHE_INFO",
 | |
|   "Roland Bouman, Daniel Black",
 | |
|   "Lists all queries in the query cache.",
 | |
|   PLUGIN_LICENSE_BSD,
 | |
|   qc_info_plugin_init, /* Plugin Init */
 | |
|   0,                          /* Plugin Deinit        */
 | |
|   0x0101,                     /* version, hex         */
 | |
|   NULL,                       /* status variables     */
 | |
|   NULL,                       /* system variables     */
 | |
|   "1.1",                      /* version as a string  */
 | |
|   MariaDB_PLUGIN_MATURITY_STABLE
 | |
| }
 | |
| maria_declare_plugin_end;
 | |
| 
 |