Commit f3d0f62d authored by gshchepa/uchum@gleb.loc's avatar gshchepa/uchum@gleb.loc
Browse files

Fixed bug #30201.

Killing a SELECT query with KILL QUERY or KILL CONNECTION
causes a server crash if the query cache is enabled.

Normal evaluation of a query may be interrupted by the
KILL QUERY/CONNECTION statement, in this case the mysql_execute_command
function returns TRUE, and the thd->killed flag has true value.
In this case the result of the query may
be cached incompletely (omitting call to query_cache_insert inside
the net_real_write function), and next call to query_cache_end_of_result
may lead to server crash.
Thus, the query_cache_end_of_result function has been modified to abort
query cache in the case of killed thread.
parent 3d44204e
Loading
Loading
Loading
Loading
+23 −14
Original line number Diff line number Diff line
@@ -710,6 +710,12 @@ void query_cache_end_of_result(THD *thd)
  if (thd->net.query_cache_query == 0)
    DBUG_VOID_RETURN;

  if (thd->killed)
  {
    query_cache_abort(&thd->net);
    DBUG_VOID_RETURN;
  }

#ifdef EMBEDDED_LIBRARY
  query_cache_insert(&thd->net, (char*)thd, 
                     emb_count_querycache_size(thd));
@@ -727,27 +733,30 @@ void query_cache_end_of_result(THD *thd)
    DUMP(&query_cache);
    BLOCK_LOCK_WR(query_block);
    Query_cache_query *header= query_block->query();
    Query_cache_block *last_result_block= header->result()->prev;
    ulong allign_size= ALIGN_SIZE(last_result_block->used);
    ulong len= max(query_cache.min_allocation_unit, allign_size);
    if (last_result_block->length >= query_cache.min_allocation_unit + len)
      query_cache.split_block(last_result_block,len);
    Query_cache_block *last_result_block;
    ulong allign_size;
    ulong len;

#ifndef DBUG_OFF
    if (header->result() == 0)
    {
      DBUG_PRINT("error", ("end of data whith no result. query '%s'",
                           header->query()));
      query_cache.wreck(__LINE__, "");

      DBUG_PRINT("error", ("End of data with no result blocks; "
                           "Query '%s' removed from cache.", header->query()));
      /*
        We do not need call of BLOCK_UNLOCK_WR(query_block); here because
        query_cache.wreck() switched query cache off but left content
        untouched for investigation (it is debugging method).
        Extra safety: empty result should not happen in the normal call
        to this function. In the release version that query should be ignored
        and removed from QC.
      */
      DBUG_ASSERT(0);
      query_cache.free_query(query_block);
      goto end;
    }
#endif

    last_result_block= header->result()->prev;
    allign_size= ALIGN_SIZE(last_result_block->used);
    len= max(query_cache.min_allocation_unit, allign_size);
    if (last_result_block->length >= query_cache.min_allocation_unit + len)
      query_cache.split_block(last_result_block,len);

    header->found_rows(current_thd->limit_found_rows);
    header->result()->type= Query_cache_block::RESULT;
    header->writer(0);