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 
00033 class Item;
00034 class Item_field;
00035 
00036 bool TableList::set_insert_values(memory::Root *)
00037 {
00038   if (table)
00039   {
00040     table->insert_values.resize(table->getShare()->rec_buff_length);
00041   }
00042 
00043   return false;
00044 }
00045 
00046 bool TableList::is_leaf_for_name_resolution()
00047 {
00048   return (is_natural_join || is_join_columns_complete || !nested_join);
00049 }
00050 
00051 TableList *TableList::find_underlying_table(Table *table_to_find)
00052 {
00053   /* is this real table and table which we are looking for? */
00054   if (table == table_to_find)
00055     return this;
00056 
00057   return NULL;
00058 }
00059 
00060 bool TableList::isCartesian() const
00061 {
00062   return false;
00063 }
00064 
00065 bool TableList::placeholder()
00066 {
00067   return derived || (create && !table->getDBStat()) || !table;
00068 }
00069 
00070 /*
00071  * The right-most child of a nested table reference is the first
00072  * element in the list of children because the children are inserted
00073  * in reverse order.
00074  */
00075 TableList *TableList::last_leaf_for_name_resolution()
00076 {
00077   TableList *cur_table_ref= this;
00078   NestedJoin *cur_nested_join;
00079 
00080   if (is_leaf_for_name_resolution())
00081     return this;
00082   assert(nested_join);
00083 
00084   for (cur_nested_join= nested_join;
00085        cur_nested_join;
00086        cur_nested_join= cur_table_ref->nested_join)
00087   {
00088     cur_table_ref= &cur_nested_join->join_list.front();
00089     /*
00090       If the current nested is a RIGHT JOIN, the operands in
00091       'join_list' are in reverse order, thus the last operand is in the
00092       end of the list.
00093     */
00094     if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
00095     {
00096       List<TableList>::iterator it(cur_nested_join->join_list.begin());
00097       TableList *next;
00098       cur_table_ref= it++;
00099       while ((next= it++))
00100         cur_table_ref= next;
00101     }
00102     if (cur_table_ref->is_leaf_for_name_resolution())
00103       break;
00104   }
00105   return cur_table_ref;
00106 }
00107 
00108 /*
00109  * The left-most child of a nested table reference is the last element
00110  * in the list of children because the children are inserted in
00111  * reverse order.
00112  */
00113 TableList *TableList::first_leaf_for_name_resolution()
00114 {
00115   TableList *cur_table_ref= NULL;
00116   NestedJoin *cur_nested_join;
00117 
00118   if (is_leaf_for_name_resolution())
00119     return this;
00120   assert(nested_join);
00121 
00122   for (cur_nested_join= nested_join;
00123        cur_nested_join;
00124        cur_nested_join= cur_table_ref->nested_join)
00125   {
00126     List<TableList>::iterator it(cur_nested_join->join_list.begin());
00127     cur_table_ref= it++;
00128     /*
00129       If the current nested join is a RIGHT JOIN, the operands in
00130       'join_list' are in reverse order, thus the first operand is
00131       already at the front of the list. Otherwise the first operand
00132       is in the end of the list of join operands.
00133     */
00134     if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
00135     {
00136       TableList *next;
00137       while ((next= it++))
00138         cur_table_ref= next;
00139     }
00140     if (cur_table_ref->is_leaf_for_name_resolution())
00141       break;
00142   }
00143   return cur_table_ref;
00144 }
00145 
00146 Item_subselect *TableList::containing_subselect()
00147 {
00148   return (select_lex ? select_lex->master_unit()->item : 0);
00149 }
00150 
00151 bool TableList::process_index_hints(Table *tbl)
00152 {
00153   /* initialize the result variables */
00154   tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
00155     tbl->keys_in_use_for_order_by= tbl->getShare()->keys_in_use;
00156 
00157   /* index hint list processing */
00158   if (index_hints)
00159   {
00160     key_map index_join[INDEX_HINT_FORCE + 1];
00161     key_map index_order[INDEX_HINT_FORCE + 1];
00162     key_map index_group[INDEX_HINT_FORCE + 1];
00163     Index_hint *hint;
00164     int type;
00165     bool have_empty_use_join= false, have_empty_use_order= false,
00166          have_empty_use_group= false;
00167     List_iterator <Index_hint> iter(index_hints->begin());
00168 
00169     /* initialize temporary variables used to collect hints of each kind */
00170     for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
00171     {
00172       index_join[type].reset();
00173       index_order[type].reset();
00174       index_group[type].reset();
00175     }
00176 
00177     /* iterate over the hints list */
00178     while ((hint= iter++))
00179     {
00180       uint32_t pos= 0;
00181 
00182       /* process empty USE INDEX () */
00183       if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
00184       {
00185         if (hint->clause & INDEX_HINT_MASK_JOIN)
00186         {
00187           index_join[hint->type].reset();
00188           have_empty_use_join= true;
00189         }
00190         if (hint->clause & INDEX_HINT_MASK_ORDER)
00191         {
00192           index_order[hint->type].reset();
00193           have_empty_use_order= true;
00194         }
00195         if (hint->clause & INDEX_HINT_MASK_GROUP)
00196         {
00197           index_group[hint->type].reset();
00198           have_empty_use_group= true;
00199         }
00200         continue;
00201       }
00202 
00203       /*
00204         Check if an index with the given name exists and get his offset in
00205         the keys bitmask for the table
00206       */
00207       if (not tbl->getShare()->doesKeyNameExist(hint->key_name.str, hint->key_name.length, pos))
00208       {
00209         my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
00210         return 1;
00211       }
00212       /* add to the appropriate clause mask */
00213       if (hint->clause & INDEX_HINT_MASK_JOIN)
00214         index_join[hint->type].set(pos);
00215       if (hint->clause & INDEX_HINT_MASK_ORDER)
00216         index_order[hint->type].set(pos);
00217       if (hint->clause & INDEX_HINT_MASK_GROUP)
00218         index_group[hint->type].set(pos);
00219     }
00220 
00221     /* cannot mix USE INDEX and FORCE INDEX */
00222     if ((index_join[INDEX_HINT_FORCE].any() ||
00223          index_order[INDEX_HINT_FORCE].any() ||
00224          index_group[INDEX_HINT_FORCE].any()) &&
00225         (index_join[INDEX_HINT_USE].any() ||  have_empty_use_join ||
00226          index_order[INDEX_HINT_USE].any() || have_empty_use_order ||
00227          index_group[INDEX_HINT_USE].any() || have_empty_use_group))
00228     {
00229       my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
00230                index_hint_type_name[INDEX_HINT_FORCE]);
00231       return 1;
00232     }
00233 
00234     /* process FORCE INDEX as USE INDEX with a flag */
00235     if (index_join[INDEX_HINT_FORCE].any() ||
00236         index_order[INDEX_HINT_FORCE].any() ||
00237         index_group[INDEX_HINT_FORCE].any())
00238     {
00239       tbl->force_index= true;
00240       index_join[INDEX_HINT_USE]|= index_join[INDEX_HINT_FORCE];
00241       index_order[INDEX_HINT_USE]|= index_order[INDEX_HINT_FORCE];
00242       index_group[INDEX_HINT_USE]|= index_group[INDEX_HINT_FORCE];
00243     }
00244 
00245     /* apply USE INDEX */
00246     if (index_join[INDEX_HINT_USE].any() || have_empty_use_join)
00247       tbl->keys_in_use_for_query&= index_join[INDEX_HINT_USE];
00248     if (index_order[INDEX_HINT_USE].any() || have_empty_use_order)
00249       tbl->keys_in_use_for_order_by&= index_order[INDEX_HINT_USE];
00250     if (index_group[INDEX_HINT_USE].any() || have_empty_use_group)
00251       tbl->keys_in_use_for_group_by&= index_group[INDEX_HINT_USE];
00252 
00253     /* apply IGNORE INDEX */
00254     key_map_subtract(tbl->keys_in_use_for_query, index_join[INDEX_HINT_IGNORE]);
00255     key_map_subtract(tbl->keys_in_use_for_order_by, index_order[INDEX_HINT_IGNORE]);
00256     key_map_subtract(tbl->keys_in_use_for_group_by, index_group[INDEX_HINT_IGNORE]);
00257   }
00258 
00259   /* make sure covering_keys don't include indexes disabled with a hint */
00260   tbl->covering_keys&= tbl->keys_in_use_for_query;
00261   return 0;
00262 }
00263 
00264 void TableList::print(Session *session, String *str)
00265 {
00266   if (nested_join)
00267   {
00268     str->append('(');
00269     print_join(session, str, &nested_join->join_list);
00270     str->append(')');
00271   }
00272   else
00273   {
00274     const char *cmp_name;                         // Name to compare with alias
00275     if (derived)
00276     {
00277       // A derived table
00278       str->append('(');
00279       derived->print(str);
00280       str->append(')');
00281       cmp_name= "";                               // Force printing of alias
00282     }
00283     else
00284     {
00285       // A normal table
00286       {
00287         str->append_identifier(db, db_length);
00288         str->append('.');
00289       }
00290       str->append_identifier(table_name, table_name_length);
00291       cmp_name= table_name;
00292     }
00293     if (my_strcasecmp(table_alias_charset, cmp_name, alias))
00294     {
00295 
00296       if (alias && alias[0])
00297       {
00298         str->append(' ');
00299 
00300         string t_alias(alias);
00301         transform(t_alias.begin(), t_alias.end(),
00302                   t_alias.begin(), ::tolower);
00303 
00304         str->append_identifier(t_alias.c_str(), t_alias.length());
00305       }
00306 
00307     }
00308 
00309     if (index_hints)
00310     {
00311       List<Index_hint>::iterator it(index_hints->begin());
00312       Index_hint *hint;
00313 
00314       while ((hint= it++))
00315       {
00316         str->append (STRING_WITH_LEN(" "));
00317         hint->print (session, str);
00318       }
00319     }
00320   }
00321 }
00322 
00323 } /* namespace drizzled */