diff options
author | unknown <acurtis@xiphis.org> | 2005-08-07 03:16:15 +0100 |
---|---|---|
committer | unknown <acurtis@xiphis.org> | 2005-08-07 03:16:15 +0100 |
commit | fdb4d307ab8c7639ced6e08c61528bfe81823fae (patch) | |
tree | 58a1759c94967db7d8ef575fe9f3af0cec92c74a /sql | |
parent | 75c06af27784e6fa6ba23f4cd6803bc7574f8253 (diff) | |
download | mariadb-git-fdb4d307ab8c7639ced6e08c61528bfe81823fae.tar.gz |
Bug#10109
"INSERT .. SELECT ... ON DUPLICATE KEY UPDATE fails"
Ensure that check_insert_fields() is only called once when
doing an INSERT..SELECT
mysql-test/r/insert_update.result:
Test for bug 10109
mysql-test/t/insert_update.test:
Test for bug 10109
sql/sql_class.h:
select_insert needs more state
sql/sql_insert.cc:
ensure that check_insert_fields() is only called once when
doing an INSERT...SELECT
sql/sql_parse.cc:
more args for select_insert constructor
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_class.h | 14 | ||||
-rw-r--r-- | sql/sql_insert.cc | 36 | ||||
-rw-r--r-- | sql/sql_parse.cc | 3 |
3 files changed, 38 insertions, 15 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h index b6bf0dcdc45..bc651b32d94 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1236,19 +1236,27 @@ class select_insert :public select_result_interceptor { List<Item> *fields; ulonglong last_insert_id; COPY_INFO info; + TABLE_LIST *insert_table_list; + TABLE_LIST *dup_table_list; select_insert(TABLE *table_par, List<Item> *fields_par, enum_duplicates duplic, bool ignore) - :table(table_par), fields(fields_par), last_insert_id(0) + :table(table_par), fields(fields_par), last_insert_id(0), + insert_table_list(0), dup_table_list(0) { bzero((char*) &info,sizeof(info)); info.ignore= ignore; info.handle_duplicates=duplic; } - select_insert(TABLE *table_par, List<Item> *fields_par, + select_insert(TABLE *table_par, + TABLE_LIST *insert_table_list_par, + TABLE_LIST *dup_table_list_par, + List<Item> *fields_par, List<Item> *update_fields, List<Item> *update_values, enum_duplicates duplic, bool ignore) - :table(table_par), fields(fields_par), last_insert_id(0) + :table(table_par), fields(fields_par), last_insert_id(0), + insert_table_list(insert_table_list_par), + dup_table_list(dup_table_list_par) { bzero((char*) &info,sizeof(info)); info.ignore= ignore; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7d613ad6fbf..8c6fed26f8e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -543,18 +543,22 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table->insert_values) DBUG_RETURN(-1); } - if ((values && check_insert_fields(thd, table, fields, *values)) || - setup_tables(insert_table_list) || - (values && setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) || - (duplic == DUP_UPDATE && - (check_update_fields(thd, table, insert_table_list, update_fields) || - setup_fields(thd, 0, dup_table_list, update_values, 1, 0, 0)))) + if (setup_tables(insert_table_list)) DBUG_RETURN(-1); - if (values && find_real_table_in_list(table_list->next, table_list->db, - table_list->real_name)) + if (values) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); - DBUG_RETURN(-1); + if (check_insert_fields(thd, table, fields, *values) || + setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || + (duplic == DUP_UPDATE && + (check_update_fields(thd, table, insert_table_list, update_fields) || + setup_fields(thd, 0, dup_table_list, update_values, 1, 0, 0)))) + DBUG_RETURN(-1); + if (find_real_table_in_list(table_list->next, table_list->db, + table_list->real_name)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); + DBUG_RETURN(-1); + } } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); @@ -1601,6 +1605,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) int res; LEX *lex= thd->lex; SELECT_LEX *lex_current_select_save= lex->current_select; + bool lex_select_no_error= lex->select_lex.no_error; DBUG_ENTER("select_insert::prepare"); unit= u; @@ -1608,10 +1613,19 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) Since table in which we are going to insert is added to the first select, LEX::current_select should point to the first select while we are fixing fields from insert list. + Since these checks may cause the query to fail, we don't want the + error messages to be converted into warnings, must force no_error=0 */ lex->current_select= &lex->select_lex; - res= check_insert_fields(thd, table, *fields, values); + lex->select_lex.no_error= 0; + res= + check_insert_fields(thd, table, *fields, values) || + setup_fields(thd, 0, insert_table_list, values, 0, 0, 0) || + (info.handle_duplicates == DUP_UPDATE && + (check_update_fields(thd, table, insert_table_list, *info.update_fields) || + setup_fields(thd, 0, dup_table_list, *info.update_values, 1, 0, 0))); lex->current_select= lex_current_select_save; + lex->select_lex.no_error= lex_select_no_error; if (res) DBUG_RETURN(1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c32cbff0f5e..9fb431df318 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2877,7 +2877,8 @@ unsent_create_error: lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates)) && - (result= new select_insert(insert_table, &lex->field_list, + (result= new select_insert(insert_table, first_local_table, + &dup_tables, &lex->field_list, &lex->update_list, &lex->value_list, lex->duplicates, lex->ignore))) { |