Skip to content

Commit c89bb15

Browse files
committed
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.
1 parent ad9d1e8 commit c89bb15

File tree

6 files changed

+116
-0
lines changed

6 files changed

+116
-0
lines changed

mysql-test/r/stat_tables.result

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,31 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
524524
CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' )
525525
NULL
526526
set use_stat_tables=@save_use_stat_tables;
527+
#
528+
# MDEV-16757: manual addition of min/max statistics for BLOB
529+
#
530+
SET use_stat_tables= PREFERABLY;
531+
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
532+
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
533+
ANALYZE TABLE t1;
534+
Table Op Msg_type Msg_text
535+
test.t1 analyze status Engine-independent statistics collected
536+
test.t1 analyze status OK
537+
SELECT * FROM mysql.column_stats;
538+
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
539+
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
540+
test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL
541+
DELETE FROM mysql.column_stats
542+
WHERE db_name='test' AND table_name='t1' AND column_name='t';
543+
INSERT INTO mysql.column_stats VALUES
544+
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
545+
SELECT * FROM mysql.column_stats;
546+
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
547+
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
548+
test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL
549+
SELECT pk FROM t1;
550+
pk
551+
1
552+
2
553+
DROP TABLE t1;
554+
set use_stat_tables=@save_use_stat_tables;

mysql-test/r/stat_tables_innodb.result

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,5 +551,33 @@ SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
551551
CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' )
552552
NULL
553553
set use_stat_tables=@save_use_stat_tables;
554+
#
555+
# MDEV-16757: manual addition of min/max statistics for BLOB
556+
#
557+
SET use_stat_tables= PREFERABLY;
558+
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
559+
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
560+
ANALYZE TABLE t1;
561+
Table Op Msg_type Msg_text
562+
test.t1 analyze status Engine-independent statistics collected
563+
test.t1 analyze status OK
564+
SELECT * FROM mysql.column_stats;
565+
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
566+
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
567+
test t1 t NULL NULL 0.0000 3.0000 NULL NULL NULL NULL
568+
DELETE FROM mysql.column_stats
569+
WHERE db_name='test' AND table_name='t1' AND column_name='t';
570+
INSERT INTO mysql.column_stats VALUES
571+
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
572+
SELECT * FROM mysql.column_stats;
573+
db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency hist_size hist_type histogram
574+
test t1 pk 1 2 0.0000 4.0000 1.0000 0 NULL NULL
575+
test t1 t bar foo 0.0000 3.0000 1.0000 0 NULL NULL
576+
SELECT pk FROM t1;
577+
pk
578+
1
579+
2
580+
DROP TABLE t1;
581+
set use_stat_tables=@save_use_stat_tables;
554582
set optimizer_switch=@save_optimizer_switch_for_stat_tables_test;
555583
SET SESSION STORAGE_ENGINE=DEFAULT;

mysql-test/t/stat_tables.test

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,27 @@ drop table t1;
312312
SET use_stat_tables = PREFERABLY;
313313
SELECT CONVERT_TZ( '1991-09-20 10:11:02', '+00:00', 'GMT' );
314314
set use_stat_tables=@save_use_stat_tables;
315+
316+
--echo #
317+
--echo # MDEV-16757: manual addition of min/max statistics for BLOB
318+
--echo #
319+
320+
SET use_stat_tables= PREFERABLY;
321+
322+
CREATE TABLE t1 (pk INT PRIMARY KEY, t TEXT);
323+
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
324+
ANALYZE TABLE t1;
325+
--sorted_result
326+
SELECT * FROM mysql.column_stats;
327+
DELETE FROM mysql.column_stats
328+
WHERE db_name='test' AND table_name='t1' AND column_name='t';
329+
INSERT INTO mysql.column_stats VALUES
330+
('test','t1','t','bar','foo', 0.0, 3.0, 1.0, 0, NULL, NULL);
331+
--sorted_result
332+
SELECT * FROM mysql.column_stats;
333+
334+
SELECT pk FROM t1;
335+
336+
DROP TABLE t1;
337+
338+
set use_stat_tables=@save_use_stat_tables;

sql/sql_statistics.cc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,6 +2916,39 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables)
29162916
}
29172917

29182918

2919+
/**
2920+
@breif
2921+
Cleanup of min/max statistical values for table share
2922+
*/
2923+
2924+
void delete_stat_values_for_table_share(TABLE_SHARE *table_share)
2925+
{
2926+
TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb;
2927+
Table_statistics *table_stats= stats_cb->table_stats;
2928+
if (!table_stats)
2929+
return;
2930+
Column_statistics *column_stats= table_stats->column_stats;
2931+
if (!column_stats)
2932+
return;
2933+
2934+
for (Field **field_ptr= table_share->field;
2935+
*field_ptr;
2936+
field_ptr++, column_stats++)
2937+
{
2938+
if (column_stats->min_value)
2939+
{
2940+
delete column_stats->min_value;
2941+
column_stats->min_value= NULL;
2942+
}
2943+
if (column_stats->max_value)
2944+
{
2945+
delete column_stats->max_value;
2946+
column_stats->max_value= NULL;
2947+
}
2948+
}
2949+
}
2950+
2951+
29192952
/**
29202953
@brief
29212954
Check whether any statistics is to be read for tables from a table list

sql/sql_statistics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables);
8989
int collect_statistics_for_table(THD *thd, TABLE *table);
9090
int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *share,
9191
bool is_safe);
92+
void delete_stat_values_for_table_share(TABLE_SHARE *table_share);
9293
int alloc_statistics_for_table(THD *thd, TABLE *table);
9394
int update_statistics_for_table(THD *thd, TABLE *table);
9495
int delete_statistics_for_table(THD *thd, LEX_STRING *db, LEX_STRING *tab);

sql/table_cache.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "hash.h"
5353
#include "table.h"
5454
#include "sql_base.h"
55+
#include "sql_statistics.h"
5556

5657
/** Configuration. */
5758
ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */
@@ -869,6 +870,7 @@ void tdc_release_share(TABLE_SHARE *share)
869870
mysql_mutex_lock(&share->tdc.LOCK_table_share);
870871
if (share->tdc.flushed)
871872
{
873+
delete_stat_values_for_table_share(share);
872874
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
873875
mysql_mutex_unlock(&LOCK_unused_shares);
874876
tdc_delete_share_from_hash(share);

0 commit comments

Comments
 (0)