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