home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / opt_sum.cpp < prev    next >
C/C++ Source or Header  |  2000-08-31  |  10KB  |  360 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /* Optimizing of many different type of queries with GROUP functions */
  19.  
  20. #include "mysql_priv.h"
  21. #include "sql_select.h"
  22.  
  23. static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
  24.  
  25. /*****************************************************************************
  26. ** This function is only called for queries with sum functions and no
  27. ** GROUP BY part.
  28. ** This substitutes constants for some COUNT(), MIN() and MAX() functions.
  29. ** The function returns 1 if all items was resolved and -1 on impossible
  30. ** conditions
  31. ****************************************************************************/
  32.  
  33. int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
  34. {
  35.   List_iterator<Item> it(all_fields);
  36.   int const_result=1;
  37.   bool recalc_const_item=0;
  38.   table_map removed_tables=0;
  39.   Item *item;
  40.  
  41.   while ((item= it++))
  42.   {
  43.     if (item->type() == Item::SUM_FUNC_ITEM)
  44.     {
  45.       Item_sum *item_sum= (((Item_sum*) item));
  46.       switch (item_sum->sum_func()) {
  47.       case Item_sum::COUNT_FUNC:
  48.     /*
  49.       If the expr in count(expr) can never be null we can change this
  50.       to the number of rows in the tables
  51.     */
  52.     if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
  53.     {
  54.       longlong count=1;
  55.       TABLE_LIST *table;
  56.       for (table=tables; table ; table=table->next)
  57.       {
  58.         if (table->on_expr || (table->table->file->option_flag() &
  59.                    HA_NOT_EXACT_COUNT))
  60.         {
  61.           const_result=0;            // Can't optimize left join
  62.           break;
  63.         }
  64.         tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
  65.         count*= table->table->file->records;
  66.       }
  67.       if (!table)
  68.       {
  69.         ((Item_sum_count*) item)->make_const(count);
  70.         recalc_const_item=1;
  71.       }
  72.     }
  73.     else
  74.       const_result=0;
  75.     break;
  76.       case Item_sum::MIN_FUNC:
  77.       {
  78.     /*
  79.       If MIN(expr) is the first part of a key or if all previous
  80.       parts of the key is found in the COND, then we can use
  81.       indexes to find the key.
  82.     */
  83.     Item *expr=item_sum->args[0];
  84.     if (expr->type() == Item::FIELD_ITEM)
  85.     {
  86.       byte key_buff[MAX_KEY_LENGTH];
  87.       TABLE_REF ref;
  88.       ref.key_buff=key_buff;
  89.  
  90.       if (!find_range_key(&ref, ((Item_field*) expr)->field,conds))
  91.       {
  92.         const_result=0;
  93.         break;
  94.       }
  95.       TABLE *table=((Item_field*) expr)->field->table;
  96.       bool error=table->file->index_init((uint) ref.key);
  97.       if (!ref.key_length)
  98.         error=table->file->index_first(table->record[0]) !=0;
  99.       else
  100.         error=table->file->index_read(table->record[0],key_buff,
  101.                       ref.key_length,
  102.                       HA_READ_KEY_OR_NEXT) ||
  103.           key_cmp(table, key_buff, ref.key, ref.key_length);
  104.       if (table->key_read)
  105.       {
  106.         table->key_read=0;
  107.         table->file->extra(HA_EXTRA_NO_KEYREAD);
  108.       }
  109.       table->file->index_end();
  110.       if (error)
  111.         return -1;                // Impossible query
  112.       removed_tables|= table->map;
  113.     }
  114.     else if (!expr->const_item())        // This is VERY seldom false
  115.     {
  116.       const_result=0;
  117.       break;
  118.     }
  119.     ((Item_sum_min*) item_sum)->reset();
  120.     ((Item_sum_min*) item_sum)->make_const();
  121.     recalc_const_item=1;
  122.     break;
  123.       }
  124.       case Item_sum::MAX_FUNC:
  125.       {
  126.     /*
  127.       If MAX(expr) is the first part of a key or if all previous
  128.       parts of the key is found in the COND, then we can use
  129.       indexes to find the key.
  130.     */
  131.     Item *expr=item_sum->args[0];
  132.     if (expr->type() == Item::FIELD_ITEM)
  133.     {
  134.       byte key_buff[MAX_KEY_LENGTH];
  135.       TABLE_REF ref;
  136.       ref.key_buff=key_buff;
  137.  
  138.       if (!find_range_key(&ref, ((Item_field*) expr)->field,conds))
  139.       {
  140.         const_result=0;
  141.         break;
  142.       }
  143.       TABLE *table=((Item_field*) expr)->field->table;
  144.       bool error=table->file->index_init((uint) ref.key);
  145.  
  146.       if (!ref.key_length)
  147.         error=table->file->index_last(table->record[0]) !=0;
  148.       else
  149.       {
  150.         (void) table->file->index_read(table->record[0], key_buff,
  151.                        ref.key_length,
  152.                        HA_READ_AFTER_KEY);
  153.         error=table->file->index_prev(table->record[0]) ||
  154.           key_cmp(table,key_buff,ref.key,ref.key_length);
  155.       }
  156.       if (table->key_read)
  157.       {
  158.         table->key_read=0;
  159.         table->file->extra(HA_EXTRA_NO_KEYREAD);
  160.       }
  161.       table->file->index_end();
  162.       if (error)
  163.         return -1;                // Impossible query
  164.       removed_tables|= table->map;
  165.     }
  166.     else if (!expr->const_item())        // This is VERY seldom false
  167.     {
  168.       const_result=0;
  169.       break;
  170.     }
  171.     ((Item_sum_min*) item_sum)->reset();
  172.     ((Item_sum_min*) item_sum)->make_const();
  173.     recalc_const_item=1;
  174.     break;
  175.       }
  176.       default:
  177.     const_result=0;
  178.     break;
  179.       }
  180.     }
  181.     else if (const_result)
  182.     {
  183.       if (recalc_const_item)
  184.     item->update_used_tables();
  185.       if (!item->const_item())
  186.     const_result=0;
  187.     }
  188.   }
  189.   if (conds && (conds->used_tables() & ~ removed_tables))
  190.     const_result=0;
  191.   return const_result;
  192. }
  193.  
  194. /* Count in how many times table is used (up to MAX_KEY_PARTS+1) */
  195.  
  196. uint count_table_entries(COND *cond,TABLE *table)
  197. {
  198.   if (cond->type() == Item::COND_ITEM)
  199.   {
  200.     if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
  201.       return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
  202.  
  203.     List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
  204.     Item *item;
  205.     uint count=0;
  206.     while ((item=li++))
  207.     {
  208.       if ((count+=count_table_entries(item,table)) > MAX_REF_PARTS)
  209.     return MAX_REF_PARTS+1;
  210.     }
  211.     return count;
  212.   }
  213.   if (cond->type() == Item::FUNC_ITEM &&
  214.       (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
  215.        (((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)) &&
  216.       cond->used_tables() == table->map)
  217.   {
  218.     Item *left_item=    ((Item_func*) cond)->arguments()[0];
  219.     Item *right_item= ((Item_func*) cond)->arguments()[1];
  220.     if (left_item->type() == Item::FIELD_ITEM)
  221.     {
  222.       if (!(((Item_field*) left_item)->field->flags & PART_KEY_FLAG) ||
  223.       !right_item->const_item())
  224.     return MAX_REF_PARTS+1;
  225.       return 1;
  226.     }
  227.     if (right_item->type() == Item::FIELD_ITEM)
  228.     {
  229.       if (!(((Item_field*) right_item)->field->flags & PART_KEY_FLAG) ||
  230.       !left_item->const_item())
  231.     return MAX_REF_PARTS+1;
  232.       return 1;
  233.     }
  234.   }
  235.   return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
  236. }
  237.  
  238.  
  239. /* check that the field is usable as key part */
  240.  
  241. bool part_of_cond(COND *cond,Field *field)
  242. {
  243.   if (cond->type() == Item::COND_ITEM)
  244.   {
  245.     if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
  246.       return 0;                    // Already checked
  247.  
  248.     List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
  249.     Item *item;
  250.     while ((item=li++))
  251.     {
  252.       if (part_of_cond(item,field))
  253.     return 1;
  254.     }
  255.     return 0;
  256.   }
  257.   if (cond->type() == Item::FUNC_ITEM &&
  258.       (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
  259.        ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC) &&
  260.       cond->used_tables() == field->table->map)
  261.   {
  262.     Item *left_item=    ((Item_func*) cond)->arguments()[0];
  263.     Item *right_item= ((Item_func*) cond)->arguments()[1];
  264.     if (left_item->type() == Item::FIELD_ITEM)
  265.     {
  266.       if (((Item_field*) left_item)->field != field ||
  267.       !right_item->const_item())
  268.     return 0;
  269.     }
  270.     else if (right_item->type() == Item::FIELD_ITEM)
  271.     {
  272.       if (((Item_field*) right_item)->field != field ||
  273.       !left_item->const_item())
  274.     return 0;
  275.       right_item=left_item;            // const item in right
  276.     }
  277.     store_val_in_field(field,right_item);
  278.     return 1;
  279.   }
  280.   return 0;
  281. }
  282.  
  283.  
  284. /* Check if we can get value for field by using a key */
  285.  
  286. static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
  287. {
  288.   if (!(field->flags & PART_KEY_FLAG))
  289.     return 0;                // Not part of a key. Skipp it
  290.  
  291.   TABLE *table=field->table;
  292.   if (table->file->option_flag() & HA_WRONG_ASCII_ORDER)
  293.     return(0);                // Can't use key to find last row
  294.   uint idx=0;
  295.  
  296.   /* Check if some key has field as first key part */
  297.   if (field->key_start && (! cond || ! (cond->used_tables() & table->map)))
  298.   {
  299.     for (key_map key=field->key_start ; !(key & 1) ; idx++)
  300.       key>>=1;
  301.     ref->key_length=0;
  302.     ref->key=idx;
  303.     if (field->part_of_key & ((table_map) 1 << idx))
  304.     {
  305.       table->key_read=1;
  306.       table->file->extra(HA_EXTRA_KEYREAD);
  307.     }
  308.     return 1;                    // Ok to use key
  309.   }
  310.   /*
  311.   ** Check if WHERE consist of exactly the previous key parts for some key
  312.   */
  313.   if (!cond)
  314.     return 0;
  315.   uint table_entries= count_table_entries(cond,table);
  316.   if (!table_entries || table_entries > MAX_REF_PARTS)
  317.     return 0;
  318.  
  319.   KEY *keyinfo,*keyinfo_end;
  320.   for (keyinfo=table->key_info, keyinfo_end=keyinfo+table->keys ;
  321.        keyinfo != keyinfo_end;
  322.        keyinfo++,idx++)
  323.   {
  324.     if (table_entries < keyinfo->key_parts)
  325.     {
  326.       byte *key_ptr=ref->key_buff;
  327.       KEY_PART_INFO *part,*part_end;
  328.       int left_length=MAX_KEY_LENGTH;
  329.  
  330.       for (part=keyinfo->key_part, part_end=part+table_entries ;
  331.        part != part_end ;
  332.        part++)
  333.       {
  334.     if (!part_of_cond(cond,part->field))
  335.       break;
  336.     // Save found constant
  337.     if (part->null_bit)
  338.       *key_ptr++= (byte) test(part->field->is_null());
  339.     if (left_length - part->length < 0)
  340.       break;                // Can't use this key
  341.     part->field->get_image((char*) key_ptr,part->length);
  342.     key_ptr+=part->length;
  343.     left_length-=part->length;
  344.       }
  345.       if (part == part_end && part->field == field)
  346.       {
  347.     ref->key_length= (uint) (key_ptr-ref->key_buff);
  348.     ref->key=idx;
  349.     if (field->part_of_key & ((table_map) 1 << idx))
  350.     {
  351.       table->key_read=1;
  352.       table->file->extra(HA_EXTRA_KEYREAD);
  353.     }
  354.     return 1;                // Ok to use key
  355.       }
  356.     }
  357.   }
  358.   return 0;                    // No possible key
  359. }
  360.