diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 1560a4be208..47c73dfb23f 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1343,3 +1343,16 @@ a 2 drop view v3,v2,v1; drop table t1; +create table t1 (a int, primary key (a)); +create view v1 as select * from t1 where a < 2 with check option; +insert into v1 values (1) on duplicate key update a=2; +insert into v1 values (1) on duplicate key update a=2; +ERROR HY000: CHECK OPTION failed +insert ignore into v1 values (1) on duplicate key update a=2; +Warnings: +Error 1359 CHECK OPTION failed +select * from t1; +a +1 +drop view v1; +drop table t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 87637fab826..b1aa198d1c8 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1296,3 +1296,16 @@ insert into v3 values (2); select * from t1; drop view v3,v2,v1; drop table t1; + +# +# CHECK OPTION with INSERT ... ON DUPLICATE KEY UPDATE +# +create table t1 (a int, primary key (a)); +create view v1 as select * from t1 where a < 2 with check option; +insert into v1 values (1) on duplicate key update a=2; +-- error 1359 +insert into v1 values (1) on duplicate key update a=2; +insert ignore into v1 values (1) on duplicate key update a=2; +select * from t1; +drop view v1; +drop table t1; diff --git a/sql/sql_class.h b/sql/sql_class.h index eccaf072008..fd05dd8d73b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -227,6 +227,9 @@ typedef struct st_copy_info { /* for INSERT ... UPDATE */ List *update_fields; List *update_values; +/* for VIEW ... WITH CHECK OPTION */ + Item *check_option; + bool ignore; } COPY_INFO; @@ -1180,14 +1183,8 @@ class select_insert :public select_result { bool insert_into_view; select_insert(TABLE_LIST *table_list_par, TABLE *table_par, - List *fields_par, enum_duplicates duplic) - :table_list(table_list_par), table(table_par), fields(fields_par), - last_insert_id(0), - insert_into_view(table_list_par && table_list_par->view != 0) - { - bzero((char*) &info,sizeof(info)); - info.handle_duplicates=duplic; - } + List *fields_par, enum_duplicates duplic, + bool ignore_check_option_errors); ~select_insert(); int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flags) { return 0; } @@ -1211,7 +1208,7 @@ public: List &fields_par, List &keys_par, List &select_fields,enum_duplicates duplic) - :select_insert (NULL, NULL, &select_fields, duplic), create_table(table), + :select_insert (NULL, NULL, &select_fields, duplic, 0), create_table(table), extra_fields(&fields_par),keys(&keys_par), create_info(create_info_par), lock(0) {} diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 9ab75a725a6..9afef1b7cb0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -242,6 +242,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, info.handle_duplicates=duplic; info.update_fields=&update_fields; info.update_values=&update_values; + info.check_option= table_list->check_option; + info.ignore= thd->lex->duplicates == DUP_IGNORE; /* Count warnings for all inserts. For single line insert, generate an error if try to set a NOT NULL field @@ -714,6 +716,24 @@ int write_record(TABLE *table,COPY_INFO *info) restore_record(table,record[1]); if (fill_record(*info->update_fields, *info->update_values, 0)) goto err; + + /* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */ + if (info->check_option && + info->check_option->val_int() == 0) + { + if (info->ignore) + { + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED)); + break; + } + else + { + my_error(ER_VIEW_CHECK_FAILED, MYF(0)); + goto err; + } + } + if ((error=table->file->update_row(table->record[1],table->record[0]))) goto err; info->updated++; @@ -1633,6 +1653,21 @@ int mysql_insert_select_prepare(THD *thd) } +select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, + List *fields_par, enum_duplicates duplic, + bool ignore_check_option_errors) + :table_list(table_list_par), table(table_par), fields(fields_par), + last_insert_id(0), + insert_into_view(table_list_par && table_list_par->view != 0) +{ + bzero((char*) &info,sizeof(info)); + info.handle_duplicates=duplic; + if (table_list_par) + info.check_option= table_list_par->check_option; + info.ignore= ignore_check_option_errors; +} + + int select_insert::prepare(List &values, SELECT_LEX_UNIT *u) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 546183563c9..e3390594cd2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2769,7 +2769,8 @@ unsent_create_error: if ((res= mysql_insert_select_prepare(thd))) break; if ((result= new select_insert(first_table, first_table->table, - &lex->field_list, lex->duplicates))) + &lex->field_list, lex->duplicates, + lex->duplicates == DUP_IGNORE))) /* Skip first table, which is the table we are inserting in */ lex->select_lex.table_list.first= (byte*) first_table->next_local; /*