Commit c89bb15c authored by Igor Babaev's avatar Igor Babaev

MDEV-16757 Memory leak after adding manually min/max statistical data

           for blob column

ANALYZE TABLE <table> does not collect statistical data on min/max values
for BLOB columns of <table>. However these values can be added into
mysql.column_stats manually by executing proper statements.
Unfortunately this led to a memory leak because the memory allocated
for these values was never freed.
This patch provides the server with a function to free memory allocated
for min/max statistical values of BLOB types.
parent ad9d1e8c
...@@ -524,3 +524,31 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); ...@@ -524,3 +524,31 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' )
NULL NULL
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;
#
# MDEV-16757: manual addition of min/max statistics for BLOB
#
SET use_stat_tables= PREFERABLY;
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SELECT * FROM mysql.column_stats;
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL
DELETE FROM mysql.column_stats
WHERE db_name='test' AND table_name='t1' AND column_name='t';
INSERT INTO mysql.column_stats VALUES
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
SELECT * FROM mysql.column_stats;
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL
SELECT pk FROM t1;
pk
1
2
DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
...@@ -551,5 +551,33 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); ...@@ -551,5 +551,33 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ) CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' )
NULL NULL
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;
#
# MDEV-16757: manual addition of min/max statistics for BLOB
#
SET use_stat_tables= PREFERABLY;
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SELECT * FROM mysql.column_stats;
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL
DELETE FROM mysql.column_stats
WHERE db_name='test' AND table_name='t1' AND column_name='t';
INSERT INTO mysql.column_stats VALUES
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
SELECT * FROM mysql.column_stats;
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL
SELECT pk FROM t1;
pk
1
2
DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test; set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
SET SESSION STORAGE_ENGINE=DEFAULT; SET SESSION STORAGE_ENGINE=DEFAULT;
...@@ -312,3 +312,27 @@ drop table t1; ...@@ -312,3 +312,27 @@ drop table t1;
SET use_stat_tables = PREFERABLY; SET use_stat_tables = PREFERABLY;
SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' ); SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;
--echo #
--echo # MDEV-16757: manual addition of min/max statistics for BLOB
--echo #
SET use_stat_tables= PREFERABLY;
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
ANALYZE TABLE t1;
--sorted_result
SELECT * FROM mysql.column_stats;
DELETE FROM mysql.column_stats
WHERE db_name='test' AND table_name='t1' AND column_name='t';
INSERT INTO mysql.column_stats VALUES
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
--sorted_result
SELECT * FROM mysql.column_stats;
SELECT pk FROM t1;
DROP TABLE t1;
set use_stat_tables=@save_use_stat_tables;
...@@ -2916,6 +2916,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) ...@@ -2916,6 +2916,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
} }
/**
@breif
Cleanup of min/max statistical values for table share
*/
void delete_stat_values_for_table_share(TABLE_SHARE *table_share)
{
TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb;
Table_statistics *table_stats= stats_cb->table_stats;
if (!table_stats)
return;
Column_statistics *column_stats= table_stats->column_stats;
if (!column_stats)
return;
for (Field **field_ptr= table_share->field;
*field_ptr;
field_ptr++, column_stats++)
{
if (column_stats->min_value)
{
delete column_stats->min_value;
column_stats->min_value= NULL;
}
if (column_stats->max_value)
{
delete column_stats->max_value;
column_stats->max_value= NULL;
}
}
}
/** /**
@brief @brief
Check whether any statistics is to be read for tables from a table list Check whether any statistics is to be read for tables from a table list
......
...@@ -89,6 +89,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables); ...@@ -89,6 +89,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables);
int collect_statistics_for_table(THD *thd, TABLE *table); int collect_statistics_for_table(THD *thd, TABLE *table);
int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share, int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share,
bool is_safe); bool is_safe);
void delete_stat_values_for_table_share(TABLE_SHARE *table_share);
int alloc_statistics_for_table(THD *thd, TABLE *table); int alloc_statistics_for_table(THD *thd, TABLE *table);
int update_statistics_for_table(THD *thd, TABLE *table); int update_statistics_for_table(THD *thd, TABLE *table);
int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab); int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab);
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "hash.h" #include "hash.h"
#include "table.h" #include "table.h"
#include "sql_base.h" #include "sql_base.h"
#include "sql_statistics.h"
/** Configuration. */ /** Configuration. */
ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */ ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */
...@@ -869,6 +870,7 @@ void tdc_release_share(TABLE_SHARE *share) ...@@ -869,6 +870,7 @@ void tdc_release_share(TABLE_SHARE *share)
mysql_mutex_lock(&share->tdc.LOCK_table_share); mysql_mutex_lock(&share->tdc.LOCK_table_share);
if (share->tdc.flushed) if (share->tdc.flushed)
{ {
delete_stat_values_for_table_share(share);
mysql_mutex_unlock(&share->tdc.LOCK_table_share); mysql_mutex_unlock(&share->tdc.LOCK_table_share);
mysql_mutex_unlock(&LOCK_unused_shares); mysql_mutex_unlock(&LOCK_unused_shares);
tdc_delete_share_from_hash(share); tdc_delete_share_from_hash(share);
......
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