diff options
Diffstat (limited to 'sql/sql_insert.cc')
-rw-r--r-- | sql/sql_insert.cc | 174 |
1 files changed, 118 insertions, 56 deletions
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2ce81d8815e..53c47706734 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd); extern "C" pthread_handler_decl(handle_delayed_insert,arg); static void unlink_blobs(register TABLE *table); #endif -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id); +static bool check_view_insertability(THD *thd, TABLE_LIST *view); /* Define to force use of my_malloc() if the allocated memory block is big */ @@ -106,7 +106,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - TABLE_LIST *save_next; + Name_resolution_context *context= &thd->lex->select_lex.context; + TABLE_LIST *save_next= table_list->next_local, + *save_context= context->table_list; + bool save_resolve_in_select_list= + thd->lex->select_lex.context.resolve_in_select_list; int res; if (fields.elements != values.elements) { @@ -115,12 +119,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } thd->dupp_field=0; - thd->lex->select_lex.no_wrap_view_item= 1; - save_next= table_list->next_local; // fields only from first table + thd->lex->select_lex.no_wrap_view_item= TRUE; + /* fields only from first table */ table_list->next_local= 0; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); + context->resolve_in_table_list_only(table_list); + res= setup_fields(thd, 0, fields, 1, 0, 0); table_list->next_local= save_next; - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= FALSE; + context->table_list= save_context; + context->resolve_in_select_list= save_resolve_in_select_list; if (res) return -1; if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) @@ -159,7 +166,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_key_in_view(thd, table_list) || (table_list->view && - check_view_insertability(table_list, thd->query_id))) + check_view_insertability(thd, table_list))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -209,7 +216,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, Check the fields we are going to modify. This will set the query_id of all used fields to the threads query_id. */ - if (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0)) + if (setup_fields(thd, 0, update_fields, 1, 0, 0)) return -1; if (table->timestamp_field) @@ -247,6 +254,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ulonglong id; COPY_INFO info; TABLE *table= 0; + TABLE_LIST *next_local; List_iterator_fast<List_item> its(values_list); List_item *values; #ifndef EMBEDDED_LIBRARY @@ -327,7 +335,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert set table_list->table if it was not set */ table= table_list->table; - // is table which we are changing used somewhere in other parts of query + next_local= table_list->next_local; + table_list->next_local= 0; + thd->lex->select_lex.context.resolve_in_table_list_only(table_list); value_count= values->elements; while ((values= its++)) { @@ -337,10 +347,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto abort; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto abort; } its.rewind (); + table_list->next_local= next_local; /* Fill in the given fields and dump it to the table file */ @@ -387,12 +398,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, MODE_STRICT_ALL_TABLES))); if ((fields.elements || !value_count) && - check_that_all_fields_are_given_values(thd, table)) + check_that_all_fields_are_given_values(thd, table, table_list)) { /* thd->net.report_error is now set, which will abort the next loop */ error= 1; } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + error= 1; + while ((values= its++)) { if (fields.elements || !value_count) @@ -596,6 +611,7 @@ abort: SYNOPSIS check_view_insertability() + thd - thread handler view - reference on VIEW IMPLEMENTATION @@ -612,7 +628,7 @@ abort: TRUE - can't be used for insert */ -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) +static bool check_view_insertability(THD * thd, TABLE_LIST *view) { uint num= view->view->select_lex.item_list.elements; TABLE *table= view->table; @@ -620,15 +636,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) *trans_end= trans_start + num; Field_translator *trans; Field **field_ptr= table->field; - query_id_t other_query_id= query_id - 1; + uint used_fields_buff_size= (table->s->fields + 7) / 8; + uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size); + MY_BITMAP used_fields; DBUG_ENTER("check_key_in_view"); + if (!used_fields_buff) + DBUG_RETURN(TRUE); // EOM + DBUG_ASSERT(view->table != 0 && view->field_translation != 0); + bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0); + bitmap_clear_all(&used_fields); + view->contain_auto_increment= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { + if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) + return TRUE; Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) @@ -636,7 +662,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ - field->field->query_id= other_query_id; /* remove collation (or other transparent for update function) if we have it @@ -648,29 +673,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) { /* Thanks to test above, we know that all columns are of type Item_field */ Item_field *field= (Item_field *)trans->item; - if (field->field->query_id == query_id) + /* check fields belong to table in which we are inserting */ + if (field->field->table == table && + bitmap_fast_test_and_set(&used_fields, field->field->field_index)) DBUG_RETURN(TRUE); - field->field->query_id= query_id; } - /* VIEW contain all fields without default value */ - for (; *field_ptr; field_ptr++) - { - Field *field= *field_ptr; - /* field have not default value */ - if ((field->type() == FIELD_TYPE_BLOB) && - (table->timestamp_field != field || - field->unireg_check == Field::TIMESTAMP_UN_FIELD)) - { - for (trans= trans_start; ; trans++) - { - if (trans == trans_end) - DBUG_RETURN(TRUE); // Field was not part of view - if (((Item_field *)trans->item)->field == *field_ptr) - break; // ok - } - } - } DBUG_RETURN(FALSE); } @@ -698,7 +706,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, where, &thd->lex->select_lex.leaf_tables, select_insert)) DBUG_RETURN(TRUE); @@ -711,7 +720,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - DBUG_RETURN(insert_view_fields(&fields, table_list)); + DBUG_RETURN(insert_view_fields(thd, &fields, table_list)); } DBUG_RETURN(FALSE); @@ -741,8 +750,10 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, enum_duplicates duplic, COND **where, bool select_insert) { + TABLE_LIST *save_table_list= thd->lex->select_lex.context.table_list; bool insert_into_view= (table_list->view != 0); - /* TODO: use this condition for 'WITH CHECK OPTION' */ + bool save_resolve_in_select_list= + thd->lex->select_lex.context.resolve_in_select_list; bool res; TABLE_LIST *next_local; DBUG_ENTER("mysql_prepare_insert"); @@ -750,6 +761,26 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, (ulong)table_list, (ulong)table, (int)insert_into_view)); + /* + For subqueries in VALUES() we should not see the table in which we are + inserting (for INSERT ... SELECT this is done by changing table_list, + because INSERT ... SELECT share SELECT_LEX it with SELECT. + */ + if (!select_insert) + { + for (SELECT_LEX_UNIT *un= thd->lex->select_lex.first_inner_unit(); + un; + un= un->next_unit()) + { + for (SELECT_LEX *sl= un->first_select(); + sl; + sl= sl->next_select()) + { + sl->context.outer_context= 0; + } + } + } + if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ @@ -763,29 +794,37 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, next_local= table_list->next_local; table_list->next_local= 0; + thd->lex->select_lex.context.resolve_in_table_list_only(table_list); if ((values && check_insert_fields(thd, table_list, fields, *values, !insert_into_view)) || - (values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) || + (values && setup_fields(thd, 0, *values, 0, 0, 0)) || (duplic == DUP_UPDATE && - ((thd->lex->select_lex.no_wrap_view_item= 1, + ((thd->lex->select_lex.no_wrap_view_item= TRUE, (res= check_update_fields(thd, table_list, update_fields)), - thd->lex->select_lex.no_wrap_view_item= 0, + thd->lex->select_lex.no_wrap_view_item= FALSE, res) || - setup_fields(thd, 0, table_list, update_values, 1, 0, 0)))) + setup_fields(thd, 0, update_values, 1, 0, 0)))) DBUG_RETURN(TRUE); table_list->next_local= next_local; - + thd->lex->select_lex.context.table_list= save_table_list; + thd->lex->select_lex.context.resolve_in_select_list= + save_resolve_in_select_list; if (!table) table= table_list->table; - if (!select_insert && unique_table(table_list, table_list->next_global)) + if (!select_insert) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + Item *fake_conds= 0; + if (unique_table(table_list, table_list->next_global)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + DBUG_RETURN(TRUE); + } + thd->lex->select_lex.fix_prepare_information(thd, &fake_conds); + thd->lex->select_lex.first_execution= 0; } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); - thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } @@ -1038,7 +1077,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list) { int err= 0; for (Field **field=entry->field ; *field ; field++) @@ -1047,10 +1087,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && ((*field)->real_type() != FIELD_TYPE_ENUM)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); + bool view= FALSE; + if (table_list) + { + table_list= (table_list->belong_to_view ? + table_list->belong_to_view : + table_list); + view= (table_list->view); + } + if (view) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, + table_list->view_name.str); + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + (*field)->field_name); + } err= 1; } } @@ -1938,7 +1997,6 @@ bool mysql_insert_select_prepare(THD *thd) SELECT_LEX do not belong to INSERT statement, so we can't add WHERE clause if table is VIEW */ - lex->query_tables->no_where_clause= 1; if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, lex->update_list, lex->value_list, @@ -1988,8 +2046,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, int select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { - int res; LEX *lex= thd->lex; + int res; SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); @@ -2043,8 +2101,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(fields->elements && - check_that_all_fields_are_given_values(thd, table)); + res= ((fields->elements && + check_that_all_fields_are_given_values(thd, table, table_list)) || + table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)); + DBUG_RETURN(res); } @@ -2290,7 +2351,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(check_that_all_fields_are_given_values(thd, table)); + DBUG_RETURN(check_that_all_fields_are_given_values(thd, table, + table_list)); } |