Drizzled Public API Documentation

table_list.cc
00001 /* Copyright (C) 2009 Sun Microsystems, Inc.
00002 
00003   This program is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU General Public License as published by
00005   the Free Software Foundation; version 2 of the License.
00006 
00007   This program is distributed in the hope that it will be useful,
00008   but WITHOUT ANY WARRANTY; without even the implied warranty of
00009   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010   GNU General Public License for more details.
00011 
00012   You should have received a copy of the GNU General Public License
00013   along with this program; if not, write to the Free Software
00014   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include <config.h>
00017 
00018 #include <string>
00019 
00020 #include <drizzled/error.h>
00021 #include <drizzled/table_list.h>
00022 #include <drizzled/item.h>
00023 #include <drizzled/item/field.h>
00024 #include <drizzled/nested_join.h>
00025 #include <drizzled/sql_lex.h>
00026 #include <drizzled/sql_select.h>
00027 
00028 using namespace std;
00029 
00030 namespace drizzled {
00031 
00032 void TableList::set_insert_values()
00033 {
00034   if (table)
00035   {
00036     table->insert_values.resize(table->getShare()->rec_buff_length);
00037   }
00038 }
00039 
00040 bool TableList::is_leaf_for_name_resolution() const
00041 {
00042   return is_natural_join || is_join_columns_complete || not nested_join;
00043 }
00044 
00045 TableList *TableList::find_underlying_table(Table *table_to_find)
00046 {
00047   /* is this real table and table which we are looking for? */
00048   if (table == table_to_find)
00049     return this;
00050 
00051   return NULL;
00052 }
00053 
00054 bool TableList::isCartesian() const
00055 {
00056   return false;
00057 }
00058 
00059 bool TableList::placeholder()
00060 {
00061   return derived || (create && !table->getDBStat()) || !table;
00062 }
00063 
00064 /*
00065  * The right-most child of a nested table reference is the first
00066  * element in the list of children because the children are inserted
00067  * in reverse order.
00068  */
00069 TableList *TableList::last_leaf_for_name_resolution()
00070 {
00071   TableList *cur_table_ref= this;
00072   NestedJoin *cur_nested_join;
00073 
00074   if (is_leaf_for_name_resolution())
00075     return this;
00076   assert(nested_join);
00077 
00078   for (cur_nested_join= nested_join;
00079        cur_nested_join;
00080        cur_nested_join= cur_table_ref->nested_join)
00081   {
00082     cur_table_ref= &cur_nested_join->join_list.front();
00083     /*
00084       If the current nested is a RIGHT JOIN, the operands in
00085       'join_list' are in reverse order, thus the last operand is in the
00086       end of the list.
00087     */
00088     if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
00089     {
00090       List<TableList>::iterator it(cur_nested_join->join_list.begin());
00091       TableList *next;
00092       cur_table_ref= it++;
00093       while ((next= it++))
00094         cur_table_ref= next;
00095     }
00096     if (cur_table_ref->is_leaf_for_name_resolution())
00097       break;
00098   }
00099   return cur_table_ref;
00100 }
00101 
00102 /*
00103  * The left-most child of a nested table reference is the last element
00104  * in the list of children because the children are inserted in
00105  * reverse order.
00106  */
00107 TableList *TableList::first_leaf_for_name_resolution()
00108 {
00109   TableList *cur_table_ref= NULL;
00110   NestedJoin *cur_nested_join;
00111 
00112   if (is_leaf_for_name_resolution())
00113     return this;
00114   assert(nested_join);
00115 
00116   for (cur_nested_join= nested_join;
00117        cur_nested_join;
00118        cur_nested_join= cur_table_ref->nested_join)
00119   {
00120     List<TableList>::iterator it(cur_nested_join->join_list.begin());
00121     cur_table_ref= it++;
00122     /*
00123       If the current nested join is a RIGHT JOIN, the operands in
00124       'join_list' are in reverse order, thus the first operand is
00125       already at the front of the list. Otherwise the first operand
00126       is in the end of the list of join operands.
00127     */
00128     if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
00129     {
00130       TableList *next;
00131       while ((next= it++))
00132         cur_table_ref= next;
00133     }
00134     if (cur_table_ref->is_leaf_for_name_resolution())
00135       break;
00136   }
00137   return cur_table_ref;
00138 }
00139 
00140 Item_subselect *TableList::containing_subselect()
00141 {
00142   return (select_lex ? select_lex->master_unit()->item : 0);
00143 }
00144 
00145 bool TableList::process_index_hints(Table *tbl)
00146 {
00147   /* initialize the result variables */
00148   tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
00149     tbl->keys_in_use_for_order_by= tbl->getShare()->keys_in_use;
00150 
00151   /* index hint list processing */
00152   if (index_hints)
00153   {
00154     key_map index_join[INDEX_HINT_FORCE + 1];
00155     key_map index_order[INDEX_HINT_FORCE + 1];
00156     key_map index_group[INDEX_HINT_FORCE + 1];
00157     bool have_empty_use_join= false, have_empty_use_order= false,
00158          have_empty_use_group= false;
00159     List_iterator <Index_hint> iter(index_hints->begin());
00160 
00161     /* initialize temporary variables used to collect hints of each kind */
00162     for (int type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
00163     {
00164       index_join[type].reset();
00165       index_order[type].reset();
00166       index_group[type].reset();
00167     }
00168 
00169     /* iterate over the hints list */
00170     while (Index_hint* hint= iter++)
00171     {
00172       /* process empty USE INDEX () */
00173       if (hint->type == INDEX_HINT_USE && !hint->key_name)
00174       {
00175         if (hint->clause & INDEX_HINT_MASK_JOIN)
00176         {
00177           index_join[hint->type].reset();
00178           have_empty_use_join= true;
00179         }
00180         if (hint->clause & INDEX_HINT_MASK_ORDER)
00181         {
00182           index_order[hint->type].reset();
00183           have_empty_use_order= true;
00184         }
00185         if (hint->clause & INDEX_HINT_MASK_GROUP)
00186         {
00187           index_group[hint->type].reset();
00188           have_empty_use_group= true;
00189         }
00190         continue;
00191       }
00192 
00193       /*
00194         Check if an index with the given name exists and get his offset in
00195         the keys bitmask for the table
00196       */
00197       uint32_t pos= tbl->getShare()->doesKeyNameExist(hint->key_name);
00198       if (pos == UINT32_MAX)
00199       {
00200         my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name, alias);
00201         return 1;
00202       }
00203       /* add to the appropriate clause mask */
00204       if (hint->clause & INDEX_HINT_MASK_JOIN)
00205         index_join[hint->type].set(pos);
00206       if (hint->clause & INDEX_HINT_MASK_ORDER)
00207         index_order[hint->type].set(pos);
00208       if (hint->clause & INDEX_HINT_MASK_GROUP)
00209         index_group[hint->type].set(pos);
00210     }
00211 
00212     /* cannot mix USE INDEX and FORCE INDEX */
00213     if ((index_join[INDEX_HINT_FORCE].any() ||
00214          index_order[INDEX_HINT_FORCE].any() ||
00215          index_group[INDEX_HINT_FORCE].any()) &&
00216         (index_join[INDEX_HINT_USE].any() ||  have_empty_use_join ||
00217          index_order[INDEX_HINT_USE].any() || have_empty_use_order ||
00218          index_group[INDEX_HINT_USE].any() || have_empty_use_group))
00219     {
00220       my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE], index_hint_type_name[INDEX_HINT_FORCE]);
00221       return 1;
00222     }
00223 
00224     /* process FORCE INDEX as USE INDEX with a flag */
00225     if (index_join[INDEX_HINT_FORCE].any() ||
00226         index_order[INDEX_HINT_FORCE].any() ||
00227         index_group[INDEX_HINT_FORCE].any())
00228     {
00229       tbl->force_index= true;
00230       index_join[INDEX_HINT_USE]|= index_join[INDEX_HINT_FORCE];
00231       index_order[INDEX_HINT_USE]|= index_order[INDEX_HINT_FORCE];
00232       index_group[INDEX_HINT_USE]|= index_group[INDEX_HINT_FORCE];
00233     }
00234 
00235     /* apply USE INDEX */
00236     if (index_join[INDEX_HINT_USE].any() || have_empty_use_join)
00237       tbl->keys_in_use_for_query&= index_join[INDEX_HINT_USE];
00238     if (index_order[INDEX_HINT_USE].any() || have_empty_use_order)
00239       tbl->keys_in_use_for_order_by&= index_order[INDEX_HINT_USE];
00240     if (index_group[INDEX_HINT_USE].any() || have_empty_use_group)
00241       tbl->keys_in_use_for_group_by&= index_group[INDEX_HINT_USE];
00242 
00243     /* apply IGNORE INDEX */
00244     key_map_subtract(tbl->keys_in_use_for_query, index_join[INDEX_HINT_IGNORE]);
00245     key_map_subtract(tbl->keys_in_use_for_order_by, index_order[INDEX_HINT_IGNORE]);
00246     key_map_subtract(tbl->keys_in_use_for_group_by, index_group[INDEX_HINT_IGNORE]);
00247   }
00248 
00249   /* make sure covering_keys don't include indexes disabled with a hint */
00250   tbl->covering_keys&= tbl->keys_in_use_for_query;
00251   return 0;
00252 }
00253 
00254 void TableList::print(Session *session, String *str)
00255 {
00256   if (nested_join)
00257   {
00258     str->append('(');
00259     print_join(session, str, &nested_join->join_list);
00260     str->append(')');
00261   }
00262   else
00263   {
00264     const char *cmp_name;                         // Name to compare with alias
00265     if (derived)
00266     {
00267       // A derived table
00268       str->append('(');
00269       derived->print(str);
00270       str->append(')');
00271       cmp_name= "";                               // Force printing of alias
00272     }
00273     else
00274     {
00275       // A normal table
00276       str->append_identifier(str_ref(schema));
00277       str->append('.');
00278       str->append_identifier(str_ref(table_name));
00279       cmp_name= table_name;
00280     }
00281     if (table_alias_charset->strcasecmp(cmp_name, alias) && alias && alias[0])
00282     {
00283       str->append(' ');
00284       str->append_identifier(boost::to_lower_copy(string(alias)));
00285     }
00286 
00287     if (index_hints)
00288     {
00289       List<Index_hint>::iterator it(index_hints->begin());
00290       while (Index_hint* hint= it++)
00291       {
00292         str->append(STRING_WITH_LEN(" "));
00293         hint->print(*str);
00294       }
00295     }
00296   }
00297 }
00298 
00299 } /* namespace drizzled */