Skip to content

Commit e226276

Browse files
committed
MDEV-10777: Server crashed due to query_cache_info plugin
Possible fix. Make the pluging more safe.
1 parent 3f5aedc commit e226276

File tree

3 files changed

+42
-9
lines changed

3 files changed

+42
-9
lines changed

plugin/qc_info/qc_info.cc

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ static ST_FIELD_INFO qc_info_fields[]=
106106
{0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
107107
};
108108

109+
110+
static const char unknown[]= "#UNKNOWN#";
111+
109112
static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
110113
COND *cond)
111114
{
@@ -146,7 +149,8 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
146149

147150
query_cache_block_raw = my_hash_element(queries, i);
148151
query_cache_block = (Query_cache_block*)query_cache_block_raw;
149-
if (query_cache_block->type != Query_cache_block::QUERY)
152+
if (unlikely(!query_cache_block ||
153+
query_cache_block->type != Query_cache_block::QUERY))
150154
continue;
151155

152156
query_cache_query = query_cache_block->query();
@@ -169,14 +173,33 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
169173
table->field[COLUMN_GROUP_CONCAT_MAX_LENGTH]->store(flags.group_concat_max_len, 0);
170174

171175
cs_client= get_charset(flags.character_set_client_num, MYF(MY_WME));
172-
table->field[COLUMN_CHARACTER_SET_CLIENT]->store(cs_client->csname, strlen(cs_client->csname), scs);
176+
if (likely(cs_client))
177+
table->field[COLUMN_CHARACTER_SET_CLIENT]->
178+
store(cs_client->csname, strlen(cs_client->csname), scs);
179+
else
180+
table->field[COLUMN_CHARACTER_SET_CLIENT]->
181+
store(STRING_WITH_LEN(unknown), scs);
182+
173183
cs_result= get_charset(flags.character_set_results_num, MYF(MY_WME));
174-
table->field[COLUMN_CHARACTER_SET_RESULT]->store(cs_result->csname, strlen(cs_result->csname), scs);
184+
if (likely(cs_result))
185+
table->field[COLUMN_CHARACTER_SET_RESULT]->
186+
store(cs_result->csname, strlen(cs_result->csname), scs);
187+
else
188+
table->field[COLUMN_CHARACTER_SET_RESULT]->
189+
store(STRING_WITH_LEN(unknown), scs);
190+
175191
collation= get_charset(flags.collation_connection_num, MYF(MY_WME));
176-
table->field[COLUMN_COLLATION]->store(collation->name, strlen(collation->name), scs);
192+
if (likely(collation))
193+
table->field[COLUMN_COLLATION]->
194+
store(collation->name, strlen(collation->name), scs);
195+
else
196+
table->field[COLUMN_COLLATION]-> store(STRING_WITH_LEN(unknown), scs);
177197

178198
tz= flags.time_zone->get_name();
179-
table->field[COLUMN_TIMEZONE]->store(tz->ptr(), tz->length(), scs);
199+
if (likely(tz))
200+
table->field[COLUMN_TIMEZONE]->store(tz->ptr(), tz->length(), scs);
201+
else
202+
table->field[COLUMN_TIMEZONE]-> store(STRING_WITH_LEN(unknown), scs);
180203
table->field[COLUMN_DEFAULT_WEEK_FORMAT]->store(flags.default_week_format, 0);
181204
table->field[COLUMN_DIV_PRECISION_INCREMENT]->store(flags.div_precision_increment, 0);
182205

@@ -204,7 +227,8 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
204227

205228
/* If we have result blocks, process them */
206229
first_result_block= query_cache_query->result();
207-
if(first_result_block)
230+
if(query_cache_query->is_results_ready() &&
231+
first_result_block)
208232
{
209233
/* initialize so we can loop over the result blocks*/
210234
result_block= first_result_block;
@@ -231,7 +255,8 @@ static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
231255
}
232256
table->field[COLUMN_RESULT_BLOCKS_COUNT]->store(result_blocks_count, 0);
233257
table->field[COLUMN_RESULT_BLOCKS_SIZE]->store(result_blocks_size, 0);
234-
table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->store(result_blocks_size_used, 0);
258+
table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->
259+
store(result_blocks_size_used, 0);
235260

236261
if (schema_table_store_record(thd, table))
237262
goto cleanup;

sql/sql_cache.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ inline void Query_cache_query::unlock_reading()
961961
void Query_cache_query::init_n_lock()
962962
{
963963
DBUG_ENTER("Query_cache_query::init_n_lock");
964-
res=0; wri = 0; len = 0;
964+
res=0; wri = 0; len = 0; ready= 0;
965965
mysql_rwlock_init(key_rwlock_query_cache_query_lock, &lock);
966966
lock_writing();
967967
DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
@@ -1226,6 +1226,7 @@ void Query_cache::end_of_result(THD *thd)
12261226
query_cache.split_block(last_result_block,len);
12271227

12281228
header->found_rows(limit_found_rows);
1229+
header->set_results_ready(); // signal for plugin
12291230
header->result()->type= Query_cache_block::RESULT;
12301231

12311232
/* Drop the writer. */

sql/sql_cache.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,9 @@ struct Query_cache_query
156156
Query_cache_block *res;
157157
Query_cache_tls *wri;
158158
ulong len;
159-
uint8 tbls_type;
160159
unsigned int last_pkt_nr;
160+
uint8 tbls_type;
161+
uint8 ready;
161162

162163
Query_cache_query() {} /* Remove gcc warning */
163164
inline void init_n_lock();
@@ -177,6 +178,12 @@ struct Query_cache_query
177178
{
178179
return (((uchar*)this) + ALIGN_SIZE(sizeof(Query_cache_query)));
179180
}
181+
/**
182+
following used to check if result ready in plugin without
183+
locking rw_lock of the query.
184+
*/
185+
inline void set_results_ready() { ready= 1; }
186+
inline bool is_results_ready() { return ready; }
180187
void lock_writing();
181188
void lock_reading();
182189
bool try_lock_writing();

0 commit comments

Comments
 (0)