Drizzled Public API Documentation

sql_derived.cc
00001 /* Copyright (C) 2002-2003 MySQL AB
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 /*
00017   Derived tables
00018   These were introduced by Sinisa <sinisa@mysql.com>
00019 */
00020 #include <config.h>
00021 
00022 #include <drizzled/sql_lex.h>
00023 #include <drizzled/select_union.h>
00024 #include <drizzled/sql_select.h>
00025 #include <drizzled/session.h>
00026 #include <drizzled/open_tables_state.h>
00027 
00028 namespace drizzled {
00029 
00030 /*
00031   Call given derived table processor (preparing or filling tables)
00032 
00033   SYNOPSIS
00034     handle_derived()
00035     lex                 LEX for this thread
00036     processor           procedure of derived table processing
00037 
00038   RETURN
00039     false  OK
00040     true   Error
00041 */
00042 bool handle_derived(LEX *lex, bool (*processor)(Session*, LEX*, TableList*))
00043 {
00044   bool res= false;
00045   if (lex->derived_tables)
00046   {
00047     lex->session->derived_tables_processing= true;
00048     for (Select_Lex *sl= lex->all_selects_list; sl; sl= sl->next_select_in_list())
00049     {
00050       for (TableList *cursor= sl->get_table_list(); cursor; cursor= cursor->next_local)
00051       {
00052         if ((res= (*processor)(lex->session, lex, cursor)))
00053           goto out;
00054       }
00055       if (lex->describe)
00056       {
00057         /*
00058           Force join->join_tmp creation, because we will use this JOIN
00059           twice for EXPLAIN and we have to have unchanged join for EXPLAINing
00060         */
00061         sl->uncacheable.set(UNCACHEABLE_EXPLAIN);
00062         sl->master_unit()->uncacheable.set(UNCACHEABLE_EXPLAIN);
00063       }
00064     }
00065   }
00066 out:
00067   lex->session->derived_tables_processing= false;
00068   return res;
00069 }
00070 
00071 /*
00072   Create temporary table structure (but do not fill it)
00073 
00074   SYNOPSIS
00075     derived_prepare()
00076     session     Thread handle
00077     lex                 LEX for this thread
00078     orig_table_list     TableList for the upper SELECT
00079 
00080   IMPLEMENTATION
00081     Derived table is resolved with temporary table.
00082 
00083     After table creation, the above TableList is updated with a new table.
00084 
00085     This function is called before any command containing derived table
00086     is executed.
00087 
00088     Derived tables is stored in session->derived_tables and freed in
00089     close_thread_tables()
00090 
00091   RETURN
00092     false  OK
00093     true   Error
00094 */
00095 bool derived_prepare(Session *session, LEX *, TableList *orig_table_list)
00096 {
00097   Select_Lex_Unit *unit= orig_table_list->derived;
00098   uint64_t create_options;
00099   bool res= false;
00100   if (unit)
00101   {
00102     Select_Lex *first_select= unit->first_select();
00103     Table *table= 0;
00104     select_union *derived_result;
00105 
00106     /* prevent name resolving out of derived table */
00107     for (Select_Lex *sl= first_select; sl; sl= sl->next_select())
00108       sl->context.outer_context= 0;
00109 
00110     derived_result= new select_union;
00111 
00112     // Select_Lex_Unit::prepare correctly work for single select
00113     if ((res= unit->prepare(session, derived_result, 0)))
00114       goto exit;
00115 
00116     create_options= (first_select->options | session->options | TMP_TABLE_ALL_COLUMNS);
00117     /*
00118       Temp table is created so that it hounours if UNION without ALL is to be
00119       processed
00120 
00121       As 'distinct' parameter we always pass false (0), because underlying
00122       query will control distinct condition by itself. Correct test of
00123       distinct underlying query will be is_union &&
00124       !unit->union_distinct->next_select() (i.e. it is union and last distinct
00125       SELECT is last SELECT of UNION).
00126     */
00127     if ((res= derived_result->create_result_table(session, &unit->types, false,
00128                                                   create_options,
00129                                                   orig_table_list->alias)))
00130       goto exit;
00131 
00132     table= derived_result->table;
00133 
00134 exit:
00135     /*
00136       if it is preparation PS only or commands that need only VIEW structure
00137       then we do not need real data and we can skip execution (and parameters
00138       is not defined, too)
00139     */
00140     if (res)
00141     {
00142       table= 0;
00143       delete derived_result;
00144     }
00145     else
00146     {
00147       orig_table_list->derived_result= derived_result;
00148       orig_table_list->table= table;
00149       orig_table_list->setTableName(table->getShare()->getTableName());
00150       table->derived_select_number= first_select->select_number;
00151       orig_table_list->setSchemaName("");
00152       /* Force read of table stats in the optimizer */
00153       table->cursor->info(HA_STATUS_VARIABLE);
00154       /* Add new temporary table to list of open derived tables */
00155       table->setNext(session->open_tables.getDerivedTables());
00156       session->open_tables.setDerivedTables(table);
00157     }
00158   }
00159 
00160   return res;
00161 }
00162 
00163 /*
00164   fill derived table
00165 
00166   SYNOPSIS
00167     derived_filling()
00168     session     Thread handle
00169     lex                 LEX for this thread
00170     unit                node that contains all SELECT's for derived tables
00171     orig_table_list     TableList for the upper SELECT
00172 
00173   IMPLEMENTATION
00174     Derived table is resolved with temporary table. It is created based on the
00175     queries defined. After temporary table is filled, if this is not EXPLAIN,
00176     then the entire unit / node is deleted. unit is deleted if UNION is used
00177     for derived table and node is deleted is it is a  simple SELECT.
00178     If you use this function, make sure it's not called at prepare.
00179     Due to evaluation of LIMIT clause it can not be used at prepared stage.
00180 
00181   RETURN
00182     false  OK
00183     true   Error
00184 */
00185 bool derived_filling(Session *session, LEX *lex, TableList *orig_table_list)
00186 {
00187   Table *table= orig_table_list->table;
00188   Select_Lex_Unit *unit= orig_table_list->derived;
00189   bool res= false;
00190 
00191   /*check that table creation pass without problem and it is derived table */
00192   if (table && unit)
00193   {
00194     Select_Lex *first_select= unit->first_select();
00195     select_union *derived_result= orig_table_list->derived_result;
00196     Select_Lex *save_current_select= lex->current_select;
00197     if (unit->is_union())
00198     {
00199       /* execute union without clean up */
00200       res= unit->exec();
00201     }
00202     else
00203     {
00204       unit->set_limit(first_select);
00205       if (unit->select_limit_cnt == HA_POS_ERROR)
00206         first_select->options&= ~OPTION_FOUND_ROWS;
00207 
00208       lex->current_select= first_select;
00209       res= select_query(session, &first_select->ref_pointer_array,
00210                         (TableList*) first_select->table_list.first,
00211                         first_select->with_wild,
00212                         first_select->item_list, first_select->where,
00213                         (first_select->order_list.elements+
00214                         first_select->group_list.elements),
00215                         (Order *) first_select->order_list.first,
00216                         (Order *) first_select->group_list.first,
00217                         first_select->having,
00218                         (first_select->options | session->options | SELECT_NO_UNLOCK),
00219                         derived_result, unit, first_select);
00220     }
00221 
00222     if (! res)
00223     {
00224       /*
00225         Here we entirely fix both TableList and list of SELECT's as
00226         there were no derived tables
00227       */
00228       if (derived_result->flush())
00229         res= true;
00230 
00231       if (! lex->describe)
00232         unit->cleanup();
00233     }
00234     else
00235       unit->cleanup();
00236     lex->current_select= save_current_select;
00237   }
00238   return res;
00239 }
00240 
00241 } /* namespace drizzled */