mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
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;
|
|
|