diff options
Diffstat (limited to 'sql/item_subselect.cc')
-rw-r--r-- | sql/item_subselect.cc | 225 |
1 files changed, 120 insertions, 105 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c615bcf7e0f..6d86d7d4b2d 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -63,12 +63,21 @@ void Item_subselect::init(st_select_lex *select_lex, => we do not copy old_engine here */ engine= unit->item->engine; + parsing_place= unit->item->parsing_place; unit->item->engine= 0; unit->item= this; engine->change_item(this, result); } else { + SELECT_LEX *outer_select= unit->outer_select(); + /* + do not take into account expression inside aggregate functions because + they can access original table fields + */ + parsing_place= (outer_select->in_sum_expr ? + NO_MATTER : + outer_select->parsing_place); if (select_lex->next_select()) engine= new subselect_union_engine(unit, result, this); else @@ -76,7 +85,7 @@ void Item_subselect::init(st_select_lex *select_lex, } { SELECT_LEX *upper= unit->outer_select(); - if (upper->parsing_place == SELECT_LEX_NODE::IN_HAVING) + if (upper->parsing_place == IN_HAVING) upper->subquery_in_having= 1; } DBUG_VOID_RETURN; @@ -123,13 +132,13 @@ Item_subselect::select_transformer(JOIN *join) bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) { + char const *save_where= thd_param->where; + int res; + DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); arena= thd->current_arena; - char const *save_where= thd->where; - int res; - if (check_stack_overrun(thd, (gptr)&res)) return 1; @@ -306,7 +315,12 @@ Item_singlerow_subselect::select_transformer(JOIN *join) return RES_OK; SELECT_LEX *select_lex= join->select_lex; - Statement backup; + + /* Juggle with current arena only if we're in prepared statement prepare */ + Item_arena *arena= join->thd->current_arena; + Item_arena backup; + if (!arena->is_stmt_prepare()) + arena= 0; // For easier test if (!select_lex->master_unit()->first_select()->next_select() && !select_lex->table_list.elements && @@ -632,6 +646,7 @@ Item_subselect::trans_res Item_in_subselect::single_value_transformer(JOIN *join, Comp_creator *func) { + Item_subselect::trans_res result= RES_ERROR; DBUG_ENTER("Item_in_subselect::single_value_transformer"); if (changed) @@ -640,10 +655,13 @@ Item_in_subselect::single_value_transformer(JOIN *join, } SELECT_LEX *select_lex= join->select_lex; - Statement backup; + Item_arena *arena= join->thd->current_arena, backup; thd->where= "scalar IN/ALL/ANY subquery"; - if (arena) + + if (!arena->is_stmt_prepare()) + arena= 0; // For easier test + else thd->set_n_backup_item_arena(arena, &backup); if (select_lex->item_list.elements > 1) @@ -751,18 +769,17 @@ Item_in_subselect::single_value_transformer(JOIN *join, } select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; - Item *item; - - item= (Item*) select_lex->item_list.head(); if (join->having || select_lex->with_sum_func || select_lex->group_list.elements) { - item= func->create(expr, - new Item_ref_null_helper(this, - select_lex->ref_pointer_array, - (char *)"<ref>", - this->full_name())); + bool tmp; + Item *item= func->create(expr, + new Item_ref_null_helper(this, + select_lex-> + ref_pointer_array, + (char *)"<ref>", + this->full_name())); /* AND and comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last @@ -770,21 +787,22 @@ Item_in_subselect::single_value_transformer(JOIN *join, */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, 0)) - { - select_lex->having_fix_field= 0; - goto err; - } + tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; + if (tmp) + goto err; } else { + Item *item= (Item*) select_lex->item_list.head(); + select_lex->item_list.empty(); select_lex->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21)); select_lex->ref_pointer_array[0]= select_lex->item_list.head(); if (select_lex->table_list.elements) { + bool tmp; Item *having= item, *orig_item= item; item= func->create(expr, item); if (!abort_on_null && orig_item->maybe_null) @@ -800,12 +818,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, new Item_cond_and(having, join->having) : having); select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, 0)) - { - select_lex->having_fix_field= 0; + tmp= join->having->fix_fields(thd, join->tables_list, 0); + select_lex->having_fix_field= 0; + if (tmp) goto err; - } - select_lex->having_fix_field= 0; item= new Item_cond_or(item, new Item_func_isnull(orig_item)); } @@ -821,6 +837,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, } else { + bool tmp; if (select_lex->master_unit()->first_select()->next_select()) { /* @@ -835,13 +852,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, (char *)"<no matter>", (char *)"<result>")); select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, - 0)) - { - select_lex->having_fix_field= 0; + tmp= join->having->fix_fields(thd, join->tables_list, 0); + select_lex->having_fix_field= 0; + if (tmp) goto err; - } - select_lex->having_fix_field= 0; } else { @@ -857,42 +871,40 @@ Item_in_subselect::single_value_transformer(JOIN *join, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SELECT_REDUCED, warn_buff); } - if (arena) - thd->restore_backup_item_arena(arena, &backup); - DBUG_RETURN(RES_REDUCE); + result= RES_REDUCE; + goto end; } } } ok: - if (arena) - thd->restore_backup_item_arena(arena, &backup); - DBUG_RETURN(RES_OK); + result= RES_OK; err: if (arena) thd->restore_backup_item_arena(arena, &backup); - DBUG_RETURN(RES_ERROR); + DBUG_RETURN(result); } Item_subselect::trans_res Item_in_subselect::row_value_transformer(JOIN *join) { + Item *item= 0; + SELECT_LEX *select_lex= join->select_lex; DBUG_ENTER("Item_in_subselect::row_value_transformer"); if (changed) { DBUG_RETURN(RES_OK); } - Statement backup; - Item *item= 0; - thd->where= "row IN/ALL/ANY subquery"; - if (arena) - thd->set_n_backup_item_arena(arena, &backup); - SELECT_LEX *select_lex= join->select_lex; + Item_arena *arena= join->thd->current_arena, backup; + if (!arena->is_stmt_prepare()) + arena= 0; + else + thd->set_n_backup_item_arena(arena, &backup); if (select_lex->item_list.elements != left_expr->cols()) { @@ -1237,29 +1249,31 @@ int subselect_uniquesubquery_engine::exec() DBUG_ENTER("subselect_uniquesubquery_engine::exec"); int error; TABLE *table= tab->table; - if ((tab->ref.key_err= (*tab->ref.key_copy)->copy())) + for (store_key **copy=tab->ref.key_copy ; *copy ; copy++) { - table->status= STATUS_NOT_FOUND; - error= -1; + if (tab->ref.key_err= (*copy)->copy()) + { + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(1); + } } + + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); + error= table->file->index_read(table->record[0], + tab->ref.key_buff, + tab->ref.key_length,HA_READ_KEY_EXACT); + if (error && error != HA_ERR_KEY_NOT_FOUND) + error= report_error(table, error); else { - if (!table->file->inited) - table->file->ha_index_init(tab->ref.key); - error= table->file->index_read(table->record[0], - tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); - if (error && error != HA_ERR_KEY_NOT_FOUND) - error= report_error(table, error); - else - { - error= 0; - table->null_row= 0; - ((Item_in_subselect *) item)->value= (!table->status && - (!cond || cond->val_int()) ? 1 : - 0); - } + error= 0; + table->null_row= 0; + ((Item_in_subselect *) item)->value= (!table->status && + (!cond || cond->val_int()) ? 1 : + 0); } + DBUG_RETURN(error != 0); } @@ -1287,55 +1301,56 @@ int subselect_indexsubquery_engine::exec() ((Item_in_subselect *) item)->was_null= 0; } - if ((*tab->ref.key_copy) && (tab->ref.key_err= (*tab->ref.key_copy)->copy())) + for (store_key **copy=tab->ref.key_copy ; *copy ; copy++) { - table->status= STATUS_NOT_FOUND; - error= -1; + if (tab->ref.key_err= (*copy)->copy()) + { + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(1); + } } + + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); + error= table->file->index_read(table->record[0], + tab->ref.key_buff, + tab->ref.key_length,HA_READ_KEY_EXACT); + if (error && error != HA_ERR_KEY_NOT_FOUND) + error= report_error(table, error); else { - if (!table->file->inited) - table->file->ha_index_init(tab->ref.key); - error= table->file->index_read(table->record[0], - tab->ref.key_buff, - tab->ref.key_length,HA_READ_KEY_EXACT); - if (error && error != HA_ERR_KEY_NOT_FOUND) - error= report_error(table, error); - else + for (;;) { - for (;;) + error= 0; + table->null_row= 0; + if (!table->status) { - error= 0; - table->null_row= 0; - if (!table->status) - { - if (!cond || cond->val_int()) - { - if (null_finding) - ((Item_in_subselect *) item)->was_null= 1; - else - ((Item_in_subselect *) item)->value= 1; - break; - } - error= table->file->index_next_same(table->record[0], - tab->ref.key_buff, - tab->ref.key_length); - if (error && error != HA_ERR_END_OF_FILE) - { - error= report_error(table, error); - break; - } - } - else - { - if (!check_null || null_finding) - break; /* We don't need to check nulls */ - *tab->ref.null_ref_key= 1; - null_finding= 1; - /* Check if there exists a row with a null value in the index */ - if ((error= (safe_index_read(tab) == 1))) - break; - } + if (!cond || cond->val_int()) + { + if (null_finding) + ((Item_in_subselect *) item)->was_null= 1; + else + ((Item_in_subselect *) item)->value= 1; + break; + } + error= table->file->index_next_same(table->record[0], + tab->ref.key_buff, + tab->ref.key_length); + if (error && error != HA_ERR_END_OF_FILE) + { + error= report_error(table, error); + break; + } + } + else + { + if (!check_null || null_finding) + break; /* We don't need to check nulls */ + *tab->ref.null_ref_key= 1; + null_finding= 1; + /* Check if there exists a row with a null value in the index */ + if ((error= (safe_index_read(tab) == 1))) + break; } } } |