Commit 01fd55cc authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-249 QUERY CACHE INFORMATION

parent e73f13a7
set global query_cache_size=1355776;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
select * from t1;
a
1
2
3
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
statement_schema statement_text result_blocks_count result_blocks_size
test select * from t1 1 512
drop table t1;
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
statement_schema statement_text result_blocks_count result_blocks_size
set global query_cache_size= default;
set global query_cache_size=1355776;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
select * from t1;
a
1
2
3
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
statement_schema statement_text result_blocks_count result_blocks_size
test select * from t1 1 512
create user mysqltest;
select a from t1;
a
1
2
3
select count(*) from information_schema.query_cache_info;
count(*)
0
drop user mysqltest;
drop table t1;
set global query_cache_size= default;
--source qc_info_init.inc
drop table t1;
# the query was invalidated
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
set global query_cache_size= default;
if (`select count(*) = 0 from information_schema.plugins where plugin_name = 'query_cache_info' and plugin_status='active'`)
{
--skip QUERY_CACHE_INFO plugin is not active
}
set global query_cache_size=1355776;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
select * from t1;
select statement_schema, statement_text, result_blocks_count, result_blocks_size from information_schema.query_cache_info;
--loose-query_cache_info
--plugin-load=$QUERY_CACHE_INFO_SO
--source include/not_embedded.inc
--source qc_info_init.inc
# try an unprivileged user
create user mysqltest;
connect (conn1,localhost,mysqltest,,);
connection conn1;
select a from t1;
select count(*) from information_schema.query_cache_info;
connection default;
drop user mysqltest;
drop table t1;
set global query_cache_size= default;
......@@ -23,8 +23,11 @@ perl;
datadir slave-load-tmpdir tmpdir socket/;
# Plugins which may or may not be there:
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster feedback debug temp-pool ssl des-key-file
xtradb thread-concurrency super-large-pages mutex-deadlock-detector null-audit maria aria pbxt oqgraph sphinx thread-handling thread-pool/;
@plugins=qw/innodb ndb archive blackhole federated partition ndbcluster
feedback debug temp-pool ssl des-key-file
xtradb thread-concurrency super-large-pages
mutex-deadlock-detector null-audit maria aria pbxt oqgraph
sphinx thread-handling thread-pool query-cache-info/;
# And substitute the content some environment variables with their
# names:
......
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include)
MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc)
/*
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.
*/
/*
* TODO: report query cache flags
*/
#ifndef MYSQL_SERVER
#define MYSQL_SERVER
#endif
#include <sql_cache.h>
#include <sql_parse.h> // check_global_access
#include <sql_acl.h> // PROCESS_ACL
#include <sql_class.h> // THD
#include <table.h> // ST_SCHEMA_TABLE
#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
/* ST_FIELD_INFO is defined in table.h */
static ST_FIELD_INFO qc_info_fields[]=
{
{"STATEMENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
{"STATEMENT_TEXT", MAX_STATEMENT_TEXT_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0},
{"RESULT_BLOCKS_COUNT", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, 0},
{"RESULT_BLOCKS_SIZE", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0},
{"RESULT_BLOCKS_SIZE_USED", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, 0},
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
};
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 status;
/* 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;
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;
const char *key, *db;
size_t key_length, db_length;
query_cache_block_raw = my_hash_element(queries, i);
query_cache_block = (Query_cache_block*)query_cache_block_raw;
if (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,
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);
/* 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(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= qc_info_fields;
schema->fill_table= qc_info_fill_table;
#ifdef _WIN32
qc = (Accessible_Query_Cache *)
GetProcAddress(GetModuleHandle(NULL), "?query_cache@@3VQuery_cache@@A");
#else
qc = (Accessible_Query_Cache *)&query_cache;
#endif
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",
"Lists all queries in the query cache.",
PLUGIN_LICENSE_BSD,
qc_info_plugin_init, /* Plugin Init */
0, /* Plugin Deinit */
0x0100, /* version, hex */
NULL, /* status variables */
NULL, /* system variables */
"1.0", /* version as a string */
MariaDB_PLUGIN_MATURITY_ALPHA
}
maria_declare_plugin_end;
......@@ -828,18 +828,18 @@ void Query_cache_block::destroy()
DBUG_VOID_RETURN;
}
inline uint Query_cache_block::headers_len()
uint Query_cache_block::headers_len()
{
return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
ALIGN_SIZE(sizeof(Query_cache_block)));
}
inline uchar* Query_cache_block::data(void)
uchar* Query_cache_block::data(void)
{
return (uchar*)( ((uchar*)this) + headers_len() );
}
inline Query_cache_query * Query_cache_block::query()
Query_cache_query * Query_cache_block::query()
{
#ifndef DBUG_OFF
if (type != QUERY)
......@@ -848,7 +848,7 @@ inline Query_cache_query * Query_cache_block::query()
return (Query_cache_query *) data();
}
inline Query_cache_table * Query_cache_block::table()
Query_cache_table * Query_cache_block::table()
{
#ifndef DBUG_OFF
if (type != TABLE)
......@@ -857,7 +857,7 @@ inline Query_cache_table * Query_cache_block::table()
return (Query_cache_table *) data();
}
inline Query_cache_result * Query_cache_block::result()
Query_cache_result * Query_cache_block::result()
{
#ifndef DBUG_OFF
if (type != RESULT && type != RES_CONT && type != RES_BEG &&
......@@ -867,7 +867,7 @@ inline Query_cache_result * Query_cache_block::result()
return (Query_cache_result *) data();
}
inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
{
return ((Query_cache_block_table *)
(((uchar*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
......
......@@ -141,12 +141,12 @@ struct Query_cache_block
inline bool is_free(void) { return type == FREE; }
void init(ulong length);
void destroy();
inline uint headers_len();
inline uchar* data(void);
inline Query_cache_query *query();
inline Query_cache_table *table();
inline Query_cache_result *result();
inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
uint headers_len();
uchar* data(void);
Query_cache_query *query();
Query_cache_table *table();
Query_cache_result *result();
Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
};
struct Query_cache_query
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment