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 
00027 namespace drizzled
00028 {
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     if (!(derived_result= new select_union))
00111       return(true); // out of memory
00112 
00113     // Select_Lex_Unit::prepare correctly work for single select
00114     if ((res= unit->prepare(session, derived_result, 0)))
00115       goto exit;
00116 
00117     create_options= (first_select->options | session->options | TMP_TABLE_ALL_COLUMNS);
00118     /*
00119       Temp table is created so that it hounours if UNION without ALL is to be
00120       processed
00121 
00122       As 'distinct' parameter we always pass false (0), because underlying
00123       query will control distinct condition by itself. Correct test of
00124       distinct underlying query will be is_union &&
00125       !unit->union_distinct->next_select() (i.e. it is union and last distinct
00126       SELECT is last SELECT of UNION).
00127     */
00128     if ((res= derived_result->create_result_table(session, &unit->types, false,
00129                                                   create_options,
00130                                                   orig_table_list->alias)))
00131       goto exit;
00132 
00133     table= derived_result->table;
00134 
00135 exit:
00136     /*
00137       if it is preparation PS only or commands that need only VIEW structure
00138       then we do not need real data and we can skip execution (and parameters
00139       is not defined, too)
00140     */
00141     if (res)
00142     {
00143       if (table)
00144       {
00145         table= 0;
00146       }
00147       delete derived_result;
00148     }
00149     else
00150     {
00151       orig_table_list->derived_result= derived_result;
00152       orig_table_list->table= table;
00153       orig_table_list->setTableName(const_cast<char *>(table->getShare()->getTableName()));
00154       orig_table_list->table_name_length= table->getShare()->getTableNameSize();
00155       table->derived_select_number= first_select->select_number;
00156       orig_table_list->setSchemaName((char *)"");
00157       orig_table_list->db_length= 0;
00158       /* Force read of table stats in the optimizer */
00159       table->cursor->info(HA_STATUS_VARIABLE);
00160       /* Add new temporary table to list of open derived tables */
00161       table->setNext(session->getDerivedTables());
00162       session->setDerivedTables(table);
00163     }
00164   }
00165 
00166   return(res);
00167 }
00168 
00169 /*
00170   fill derived table
00171 
00172   SYNOPSIS
00173     derived_filling()
00174     session     Thread handle
00175     lex                 LEX for this thread
00176     unit                node that contains all SELECT's for derived tables
00177     orig_table_list     TableList for the upper SELECT
00178 
00179   IMPLEMENTATION
00180     Derived table is resolved with temporary table. It is created based on the
00181     queries defined. After temporary table is filled, if this is not EXPLAIN,
00182     then the entire unit / node is deleted. unit is deleted if UNION is used
00183     for derived table and node is deleted is it is a  simple SELECT.
00184     If you use this function, make sure it's not called at prepare.
00185     Due to evaluation of LIMIT clause it can not be used at prepared stage.
00186 
00187   RETURN
00188     false  OK
00189     true   Error
00190 */
00191 bool derived_filling(Session *session, LEX *lex, TableList *orig_table_list)
00192 {
00193   Table *table= orig_table_list->table;
00194   Select_Lex_Unit *unit= orig_table_list->derived;
00195   bool res= false;
00196 
00197   /*check that table creation pass without problem and it is derived table */
00198   if (table && unit)
00199   {
00200     Select_Lex *first_select= unit->first_select();
00201     select_union *derived_result= orig_table_list->derived_result;
00202     Select_Lex *save_current_select= lex->current_select;
00203     if (unit->is_union())
00204     {
00205       /* execute union without clean up */
00206       res= unit->exec();
00207     }
00208     else
00209     {
00210       unit->set_limit(first_select);
00211       if (unit->select_limit_cnt == HA_POS_ERROR)
00212         first_select->options&= ~OPTION_FOUND_ROWS;
00213 
00214       lex->current_select= first_select;
00215       res= select_query(session, &first_select->ref_pointer_array,
00216                         (TableList*) first_select->table_list.first,
00217                         first_select->with_wild,
00218                         first_select->item_list, first_select->where,
00219                         (first_select->order_list.elements+
00220                         first_select->group_list.elements),
00221                         (Order *) first_select->order_list.first,
00222                         (Order *) first_select->group_list.first,
00223                         first_select->having,
00224                         (first_select->options | session->options | SELECT_NO_UNLOCK),
00225                         derived_result, unit, first_select);
00226     }
00227 
00228     if (! res)
00229     {
00230       /*
00231         Here we entirely fix both TableList and list of SELECT's as
00232         there were no derived tables
00233       */
00234       if (derived_result->flush())
00235         res= true;
00236 
00237       if (! lex->describe)
00238         unit->cleanup();
00239     }
00240     else
00241       unit->cleanup();
00242     lex->current_select= save_current_select;
00243   }
00244   return res;
00245 }
00246 
00247 } /* namespace drizzled */