Drizzled Public API Documentation

scan.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Padraig O'Sullivan
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 #include <drizzled/join_table.h>
00023 #include <drizzled/table.h>
00024 #include <drizzled/sql_select.h>
00025 #include <drizzled/internal/my_sys.h>
00026 #include <drizzled/optimizer/access_method/scan.h>
00027 #include <drizzled/util/test.h>
00028 #include <drizzled/statistics_variables.h>
00029 #include <drizzled/session.h>
00030 
00031 using namespace drizzled;
00032 
00033 static uint32_t make_join_orderinfo(Join *join);
00034 
00035 void optimizer::Scan::getStats(Table& table, JoinTable& join_tab)
00036 {
00037   Join *join= join_tab.join;
00038   bool statistics= test(! (join->select_options & SELECT_DESCRIBE));
00039   uint64_t options= (join->select_options &
00040                      (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) |
00041                      (0);
00042   uint32_t no_jbuf_after= make_join_orderinfo(join);
00043   uint32_t index= &join_tab - join->join_tab;
00044 
00045   /*
00046    * If previous table use cache
00047    * If the incoming data set is already sorted don't use cache.
00048    */
00049   table.status= STATUS_NO_RECORD;
00050 
00051   if (index != join->const_tables && 
00052       ! (options & SELECT_NO_JOIN_CACHE) &&
00053       join_tab.use_quick != 2 && 
00054       ! join_tab.first_inner && 
00055       index <= no_jbuf_after &&
00056       ! join_tab.insideout_match_tab)
00057   {
00058     if ((options & SELECT_DESCRIBE) ||
00059         ! join_init_cache(join->session,
00060                           join->join_tab + join->const_tables,
00061                           index - join->const_tables))
00062     {
00063       (&join_tab)[-1].next_select= sub_select_cache; /* Patch previous */
00064     }
00065   }
00066 
00067   /* These init changes read_record */
00068   if (join_tab.use_quick == 2)
00069   {
00070     join->session->server_status|= SERVER_QUERY_NO_GOOD_INDEX_USED;
00071     join_tab.read_first_record= join_init_quick_read_record;
00072     if (statistics)
00073     {
00074       join->session->status_var.select_range_check_count++;
00075     }
00076   }
00077   else
00078   {
00079     join_tab.read_first_record= join_init_read_record;
00080     if (index == join->const_tables)
00081     {
00082       if (join_tab.select && join_tab.select->quick)
00083       {
00084         if (statistics)
00085           join->session->status_var.select_range_count++;
00086       }
00087       else
00088       {
00089         join->session->server_status|= SERVER_QUERY_NO_INDEX_USED;
00090         if (statistics)
00091           join->session->status_var.select_scan_count++;
00092       }
00093     }
00094     else
00095     {
00096       if (join_tab.select && join_tab.select->quick)
00097       {
00098         if (statistics)
00099           join->session->status_var.select_full_range_join_count++;
00100       }
00101       else
00102       {
00103         join->session->server_status|= SERVER_QUERY_NO_INDEX_USED;
00104         if (statistics)
00105           join->session->status_var.select_full_join_count++;
00106       }
00107     }
00108     if (! table.no_keyread)
00109     {
00110       if (join_tab.select && 
00111           join_tab.select->quick &&
00112           join_tab.select->quick->index != MAX_KEY && //not index_merge
00113           table.covering_keys.test(join_tab.select->quick->index))
00114       {
00115         table.key_read= 1;
00116         table.cursor->extra(HA_EXTRA_KEYREAD);
00117       }
00118       else if (! table.covering_keys.none() && ! (join_tab.select && join_tab.select->quick))
00119       { // Only read index tree
00120         if (! join_tab.insideout_match_tab)
00121         {
00122           /*
00123              See bug #26447: "Using the clustered index for a table scan
00124              is always faster than using a secondary index".
00125            */
00126           if (table.getShare()->hasPrimaryKey() &&
00127               table.cursor->primary_key_is_clustered())
00128           {
00129             join_tab.index= table.getShare()->getPrimaryKey();
00130           }
00131           else
00132           {
00133             join_tab.index= table.find_shortest_key(&table.covering_keys);
00134           }
00135         }
00136         join_tab.read_first_record= join_read_first;
00137         join_tab.type= AM_NEXT; // Read with index_first / index_next
00138       }
00139     }
00140   }
00141 }
00142 
00152 static uint32_t make_join_orderinfo(Join *join)
00153 {
00154   if (join->need_tmp)
00155     return join->tables;
00156 
00157   uint32_t i= join->const_tables;
00158   for (; i < join->tables; i++)
00159   {
00160     JoinTable *tab= join->join_tab + i;
00161     Table *table= tab->table;
00162     if ((table == join->sort_by_table &&
00163         (! join->order || join->skip_sort_order)) ||
00164         (join->sort_by_table == (Table *) 1 &&  i != join->const_tables))
00165     {
00166       break;
00167     }
00168   }
00169   return i;
00170 }