Drizzled Public API Documentation

ref.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2008 Sun Microsystems, Inc.
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; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <drizzled/session.h>
00023 #include <drizzled/error.h>
00024 #include <drizzled/show.h>
00025 #include <drizzled/item/ref.h>
00026 #include <drizzled/plugin/client.h>
00027 #include <drizzled/item/sum.h>
00028 #include <drizzled/item/subselect.h>
00029 #include <drizzled/sql_lex.h>
00030 
00031 namespace drizzled {
00032 
00033 Item_ref::Item_ref(Name_resolution_context *context_arg,
00034                    Item **item, const char *table_name_arg,
00035                    const char *field_name_arg,
00036                    bool alias_name_used_arg)
00037   :Item_ident(context_arg, NULL, table_name_arg, field_name_arg),
00038    result_field(0), ref(item)
00039 {
00040   alias_name_used= alias_name_used_arg;
00041   /*
00042     This constructor used to create some internals references over fixed items
00043   */
00044   if (ref && *ref && (*ref)->fixed)
00045     set_properties();
00046 }
00047 
00048 
00113 bool Item_ref::fix_fields(Session *session, Item **reference)
00114 {
00115   enum_parsing_place place= NO_MATTER;
00116   assert(fixed == 0);
00117   Select_Lex *current_sel= session->lex().current_select;
00118 
00119   if (!ref || ref == not_found_item)
00120   {
00121     if (!(ref= resolve_ref_in_select_and_group(session, this, context->select_lex)))
00122       return true;             /* Some error occurred (e.g. ambiguous names). */
00123 
00124     if (ref == not_found_item) /* This reference was not resolved. */
00125     {
00126       Name_resolution_context *last_checked_context= context;
00127       Name_resolution_context *outer_context= context->outer_context;
00128       Field *from_field;
00129       ref= 0;
00130 
00131       if (!outer_context)
00132       {
00133         /* The current reference cannot be resolved in this query. */
00134         my_error(ER_BAD_FIELD_ERROR,MYF(0), full_name(), session->where());
00135         return true;
00136       }
00137 
00138       /*
00139         If there is an outer context (select), and it is not a derived table
00140         (which do not support the use of outer fields for now), try to
00141         resolve this reference in the outer select(s).
00142 
00143         We treat each subselect as a separate namespace, so that different
00144         subselects may contain columns with the same names. The subselects are
00145         searched starting from the innermost.
00146       */
00147       from_field= (Field*) not_found_field;
00148 
00149       do
00150       {
00151         Select_Lex *select= outer_context->select_lex;
00152         Item_subselect *prev_subselect_item=
00153           last_checked_context->select_lex->master_unit()->item;
00154         last_checked_context= outer_context;
00155 
00156         /* Search in the SELECT and GROUP lists of the outer select. */
00157         if (outer_context->resolve_in_select_list)
00158         {
00159           if (!(ref= resolve_ref_in_select_and_group(session, this, select)))
00160             return true; /* Some error occurred (e.g. ambiguous names). */
00161           if (ref != not_found_item)
00162           {
00163             assert(*ref && (*ref)->fixed);
00164             prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
00165             prev_subselect_item->const_item_cache&= (*ref)->const_item();
00166             break;
00167           }
00168           /*
00169             Set ref to 0 to ensure that we get an error in case we replaced
00170             this item with another item and still use this item in some
00171             other place of the parse tree.
00172           */
00173           ref= 0;
00174         }
00175 
00176         place= prev_subselect_item->parsing_place;
00177         /*
00178           Check table fields only if the subquery is used somewhere out of
00179           HAVING or the outer SELECT does not use grouping (i.e. tables are
00180           accessible).
00181           TODO:
00182           Here we could first find the field anyway, and then test this
00183           condition, so that we can give a better error message -
00184           ER_WRONG_FIELD_WITH_GROUP, instead of the less informative
00185           ER_BAD_FIELD_ERROR which we produce now.
00186 
00187           @todo determine if this is valid.
00188         */
00189         if ((place != IN_HAVING ||
00190              (!select->with_sum_func &&
00191               select->group_list.elements == 0)))
00192         {
00193           /*
00194             In case of view, find_field_in_tables() write pointer to view
00195             field expression to 'reference', i.e. it substitute that
00196             expression instead of this Item_ref
00197           */
00198           from_field= find_field_in_tables(session, this,
00199                                            outer_context->
00200                                              first_name_resolution_table,
00201                                            outer_context->
00202                                              last_name_resolution_table,
00203                                            reference,
00204                                            IGNORE_EXCEPT_NON_UNIQUE, true);
00205           if (! from_field)
00206             return true;
00207           if (from_field == view_ref_found)
00208           {
00209             Item::Type refer_type= (*reference)->type();
00210             prev_subselect_item->used_tables_cache|=
00211               (*reference)->used_tables();
00212             prev_subselect_item->const_item_cache&=
00213               (*reference)->const_item();
00214             assert((*reference)->type() == REF_ITEM);
00215             mark_as_dependent(session, last_checked_context->select_lex,
00216                               context->select_lex, this,
00217                               ((refer_type == REF_ITEM ||
00218                                 refer_type == FIELD_ITEM) ?
00219                                (Item_ident*) (*reference) :
00220                                0));
00221             /*
00222               view reference found, we substituted it instead of this
00223               Item, so can quit
00224             */
00225             return false;
00226           }
00227           if (from_field != not_found_field)
00228           {
00229             if (cached_table && cached_table->select_lex &&
00230                 outer_context->select_lex &&
00231                 cached_table->select_lex != outer_context->select_lex)
00232             {
00233               /*
00234                 Due to cache, find_field_in_tables() can return field which
00235                 doesn't belong to provided outer_context. In this case we have
00236                 to find proper field context in order to fix field correcly.
00237               */
00238               do
00239               {
00240                 outer_context= outer_context->outer_context;
00241                 select= outer_context->select_lex;
00242                 prev_subselect_item=
00243                   last_checked_context->select_lex->master_unit()->item;
00244                 last_checked_context= outer_context;
00245               } while (outer_context && outer_context->select_lex &&
00246                        cached_table->select_lex != outer_context->select_lex);
00247             }
00248             prev_subselect_item->used_tables_cache|= from_field->getTable()->map;
00249             prev_subselect_item->const_item_cache= false;
00250             break;
00251           }
00252         }
00253         assert(from_field == not_found_field);
00254 
00255         /* Reference is not found => depend on outer (or just error). */
00256         prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT;
00257         prev_subselect_item->const_item_cache= false;
00258 
00259         outer_context= outer_context->outer_context;
00260       } while (outer_context);
00261 
00262       assert(from_field != 0 && from_field != view_ref_found);
00263       if (from_field != not_found_field)
00264       {
00265         Item_field* fld;
00266         fld= new Item_field(from_field);
00267         *reference= fld;
00268         mark_as_dependent(session, last_checked_context->select_lex,
00269                           session->lex().current_select, this, fld);
00270         /*
00271           A reference is resolved to a nest level that's outer or the same as
00272           the nest level of the enclosing set function : adjust the value of
00273           max_arg_level for the function if it's needed.
00274         */
00275         if (session->lex().in_sum_func &&
00276             session->lex().in_sum_func->nest_level >=
00277             last_checked_context->select_lex->nest_level)
00278           set_if_bigger(session->lex().in_sum_func->max_arg_level,
00279                         last_checked_context->select_lex->nest_level);
00280         return false;
00281       }
00282       if (ref == 0)
00283       {
00284         /* The item was not a table field and not a reference */
00285         my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), session->where());
00286         return true;
00287       }
00288       /* Should be checked in resolve_ref_in_select_and_group(). */
00289       assert(*ref && (*ref)->fixed);
00290       mark_as_dependent(session, last_checked_context->select_lex,
00291                         context->select_lex, this, this);
00292       /*
00293         A reference is resolved to a nest level that's outer or the same as
00294         the nest level of the enclosing set function : adjust the value of
00295         max_arg_level for the function if it's needed.
00296       */
00297       if (session->lex().in_sum_func &&
00298           session->lex().in_sum_func->nest_level >=
00299           last_checked_context->select_lex->nest_level)
00300         set_if_bigger(session->lex().in_sum_func->max_arg_level,
00301                       last_checked_context->select_lex->nest_level);
00302     }
00303   }
00304 
00305   assert(*ref);
00306   /*
00307     Check if this is an incorrect reference in a group function or forward
00308     reference. Do not issue an error if this is:
00309       1. outer reference (will be fixed later by the fix_inner_refs function);
00310       2. an unnamed reference inside an aggregate function.
00311   */
00312   if (!((*ref)->type() == REF_ITEM &&
00313        ((Item_ref *)(*ref))->ref_type() == OUTER_REF) &&
00314       (((*ref)->with_sum_func && name &&
00315         !(current_sel->linkage != GLOBAL_OPTIONS_TYPE &&
00316           current_sel->having_fix_field)) ||
00317        !(*ref)->fixed))
00318   {
00319     my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, ((*ref)->with_sum_func ? "reference to group function" : "forward reference in item list"));
00320     return true;
00321   }
00322 
00323   set_properties();
00324 
00325   if ((*ref)->check_cols(1))
00326     return true;
00327   return false;
00328 }
00329 
00330 
00331 void Item_ref::set_properties()
00332 {
00333   max_length= (*ref)->max_length;
00334   maybe_null= (*ref)->maybe_null;
00335   decimals=   (*ref)->decimals;
00336   collation.set((*ref)->collation);
00337   /*
00338     We have to remember if we refer to a sum function, to ensure that
00339     split_sum_func() doesn't try to change the reference.
00340   */
00341   with_sum_func= (*ref)->with_sum_func;
00342   unsigned_flag= (*ref)->unsigned_flag;
00343   fixed= 1;
00344   if (alias_name_used)
00345     return;
00346   if ((*ref)->type() == FIELD_ITEM)
00347     alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
00348   else
00349     alias_name_used= true; // it is not field, so it is was resolved by alias
00350 }
00351 
00352 
00353 void Item_ref::cleanup()
00354 {
00355   Item_ident::cleanup();
00356   result_field= 0;
00357   return;
00358 }
00359 
00360 
00361 void Item_ref::print(String *str)
00362 {
00363   if (ref)
00364   {
00365     if ((*ref)->type() != Item::CACHE_ITEM &&
00366         !table_name && name && alias_name_used)
00367     {
00368       str->append_identifier(str_ref(name));
00369     }
00370     else
00371       (*ref)->print(str);
00372   }
00373   else
00374     Item_ident::print(str);
00375 }
00376 
00377 
00378 void Item_ref::send(plugin::Client *client, String *tmp)
00379 {
00380   if (result_field)
00381   {
00382     client->store(result_field);
00383     return;
00384   }
00385   return (*ref)->send(client, tmp);
00386 }
00387 
00388 
00389 double Item_ref::val_result()
00390 {
00391   if (result_field)
00392   {
00393     if ((null_value= result_field->is_null()))
00394       return 0.0;
00395     return result_field->val_real();
00396   }
00397   return val_real();
00398 }
00399 
00400 
00401 int64_t Item_ref::val_int_result()
00402 {
00403   if (result_field)
00404   {
00405     if ((null_value= result_field->is_null()))
00406       return 0;
00407     return result_field->val_int();
00408   }
00409   return val_int();
00410 }
00411 
00412 
00413 String *Item_ref::str_result(String* str)
00414 {
00415   if (result_field)
00416   {
00417     if ((null_value= result_field->is_null()))
00418       return 0;
00419     str->set_charset(str_value.charset());
00420     return result_field->val_str(str, &str_value);
00421   }
00422   return val_str(str);
00423 }
00424 
00425 
00426 type::Decimal *Item_ref::val_decimal_result(type::Decimal *decimal_value)
00427 {
00428   if (result_field)
00429   {
00430     if ((null_value= result_field->is_null()))
00431       return 0;
00432     return result_field->val_decimal(decimal_value);
00433   }
00434   return val_decimal(decimal_value);
00435 }
00436 
00437 
00438 bool Item_ref::val_bool_result()
00439 {
00440   if (result_field)
00441   {
00442     if ((null_value= result_field->is_null()))
00443       return 0;
00444     switch (result_field->result_type()) {
00445     case INT_RESULT:
00446       return result_field->val_int() != 0;
00447 
00448     case DECIMAL_RESULT:
00449       {
00450         type::Decimal decimal_value;
00451         type::Decimal *val= result_field->val_decimal(&decimal_value);
00452         if (val)
00453           return not val->isZero();
00454         return 0;
00455       }
00456 
00457     case REAL_RESULT:
00458     case STRING_RESULT:
00459       return result_field->val_real() != 0.0;
00460 
00461     case ROW_RESULT:
00462       assert(0);
00463     }
00464   }
00465 
00466   return val_bool();
00467 }
00468 
00469 
00470 double Item_ref::val_real()
00471 {
00472   assert(fixed);
00473   double tmp=(*ref)->val_result();
00474   null_value=(*ref)->null_value;
00475   return tmp;
00476 }
00477 
00478 
00479 int64_t Item_ref::val_int()
00480 {
00481   assert(fixed);
00482   int64_t tmp=(*ref)->val_int_result();
00483   null_value=(*ref)->null_value;
00484   return tmp;
00485 }
00486 
00487 
00488 bool Item_ref::val_bool()
00489 {
00490   assert(fixed);
00491   bool tmp= (*ref)->val_bool_result();
00492   null_value= (*ref)->null_value;
00493   return tmp;
00494 }
00495 
00496 
00497 String *Item_ref::val_str(String* tmp)
00498 {
00499   assert(fixed);
00500   tmp=(*ref)->str_result(tmp);
00501   null_value=(*ref)->null_value;
00502   return tmp;
00503 }
00504 
00505 
00506 bool Item_ref::is_null()
00507 {
00508   assert(fixed);
00509   return (*ref)->is_null();
00510 }
00511 
00512 
00513 bool Item_ref::get_date(type::Time &ltime,uint32_t fuzzydate)
00514 {
00515   return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
00516 }
00517 
00518 
00519 type::Decimal *Item_ref::val_decimal(type::Decimal *decimal_value)
00520 {
00521   type::Decimal *val= (*ref)->val_decimal_result(decimal_value);
00522   null_value= (*ref)->null_value;
00523   return val;
00524 }
00525 
00526 int Item_ref::save_in_field(Field *to, bool no_conversions)
00527 {
00528   int res;
00529   assert(!result_field);
00530   res= (*ref)->save_in_field(to, no_conversions);
00531   null_value= (*ref)->null_value;
00532   return res;
00533 }
00534 
00535 
00536 void Item_ref::save_org_in_field(Field *field)
00537 {
00538   (*ref)->save_org_in_field(field);
00539 }
00540 
00541 
00542 void Item_ref::make_field(SendField *field)
00543 {
00544   (*ref)->make_field(field);
00545   /* Non-zero in case of a view */
00546   if (name)
00547     field->col_name= name;
00548   if (table_name)
00549     field->table_name= table_name;
00550   if (db_name)
00551     field->db_name= db_name;
00552 }
00553 
00554 
00555 Item *Item_ref::get_tmp_table_item(Session *session)
00556 {
00557   if (!result_field)
00558     return (*ref)->get_tmp_table_item(session);
00559 
00560   Item_field *item= new Item_field(result_field);
00561   if (item)
00562   {
00563     item->table_name= table_name;
00564     item->db_name= db_name;
00565   }
00566   return item;
00567 }
00568 
00569 void Item_ref::fix_after_pullout(Select_Lex *new_parent, Item **)
00570 {
00571   if (depended_from == new_parent)
00572   {
00573     (*ref)->fix_after_pullout(new_parent, ref);
00574     depended_from= NULL;
00575   }
00576 }
00577 
00578 } /* namespace drizzled */