diff options
Diffstat (limited to 'sql/item_subselect.cc')
-rw-r--r-- | sql/item_subselect.cc | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc new file mode 100644 index 00000000000..b0a94f0b8e6 --- /dev/null +++ b/sql/item_subselect.cc @@ -0,0 +1,211 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + subselect Item + +SUBSELECT TODO: + - add function from mysql_select that use JOIN* as parameter to JOIN methods + (sql_select.h/sql_select.cc) + - remove double 'having' & 'having_list' from JOIN + (sql_select.h/sql_select.cc) + + - subselect in HAVING clause + - add subselect union select (sql_union.cc) + +*/ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include "sql_select.h" + +Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex, + select_subselect *result): + assigned(0), executed(0), optimized(0), error(0) +{ + DBUG_ENTER("Item_subselect::Item_subselect"); + DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); + this->result= result; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + unit->offset_limit_cnt= unit->global_parameters->offset_limit; + unit->select_limit_cnt= unit->global_parameters->select_limit+ + unit->global_parameters ->offset_limit; + if (unit->select_limit_cnt < unit->global_parameters->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; + join= new JOIN(thd, select_lex->item_list, select_lex->options, result); + if (!join || !result) + { + //out of memory + thd->fatal_error= 1; + my_printf_error(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + this->select_lex= select_lex; + assign_null(); + /* + item value is NULL if select_subselect not changed this value + (i.e. some rows will be found returned) + */ + null_value= 1; + DBUG_VOID_RETURN; +} + +void Item_subselect::make_field (Send_field *tmp_field) +{ + if (null_value) + { + init_make_field(tmp_field,FIELD_TYPE_NULL); + tmp_field->length=4; + } else { + init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? + FIELD_TYPE_VAR_STRING : + (result_type() == INT_RESULT) ? + FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); + } +} + +bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + // Is it one field subselect? + if (select_lex->item_list.elements > max_columns) + { + my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); + return 1; + } + SELECT_LEX *save_select= thd->lex.select; + thd->lex.select= select_lex; + if(join->prepare((TABLE_LIST*) select_lex->table_list.first, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) 0, select_lex, + select_lex->master_unit())) + return 1; + thd->lex.select= save_select; + return 0; +} + +int Item_subselect::exec() +{ + DBUG_ENTER("Item_subselect::exec"); + if (!optimized) + { + optimized=1; + if (join->optimize()) + { + executed= 1; + DBUG_RETURN(join->error?join->error:1); + } + } + if (join->select_lex->depended && executed) + { + if (join->reinit()) + { + error= 1; + DBUG_RETURN(1); + } + assign_null(); + executed= assigned= 0; + } + if (!executed) + { + SELECT_LEX *save_select= join->thd->lex.select; + join->thd->lex.select= select_lex; + join->exec(); + join->thd->lex.select= save_select; + executed= 1; + DBUG_RETURN(join->error); + } + DBUG_RETURN(0); +} + +inline table_map Item_subselect::used_tables() const +{ + return (table_map) select_lex->depended ? 1L : 0L; +} + +Item_singleval_subselect::Item_singleval_subselect(THD *thd, + st_select_lex *select_lex): + Item_subselect(thd, select_lex, new select_singleval_subselect(this)) +{ + max_columns= 1; + maybe_null= 1; +} + +Item::Type Item_subselect::type() const +{ + return SUBSELECT_ITEM; +} + +double Item_singleval_subselect::val () +{ + if (exec()) + return 0; + return real_value; +} + +longlong Item_singleval_subselect::val_int () +{ + if (exec()) + return 0; + return int_value; +} + +String *Item_singleval_subselect::val_str (String *str) +{ + if (exec() || null_value) + return 0; + return &str_value; +} + +Item_exists_subselect::Item_exists_subselect(THD *thd, + st_select_lex *select_lex): + Item_subselect(thd, select_lex, new select_exists_subselect(this)) +{ + max_columns= UINT_MAX; + null_value= 0; //can't be NULL + maybe_null= 0; //can't be NULL + value= 0; + select_lex->select_limit= 1; // we need only 1 row to determinate existence +} + +double Item_exists_subselect::val () +{ + if (exec()) + return 0; + return (double) value; +} + +longlong Item_exists_subselect::val_int () +{ + if (exec()) + return 0; + return value; +} + +String *Item_exists_subselect::val_str(String *str) +{ + if (exec()) + return 0; + str->set(value); + return str; +} + |