From: Date: May 23 2007 4:57pm Subject: bk commit into 5.0 tree (gshchepa:1.2491) BUG#27827 List-Archive: http://lists.mysql.com/commits/27219 X-Bug: 27827 Message-Id: <20070523145744.8FDD73D40F9@localhost.localdomain> Below is the list of changes that have just been committed into a local 5.0 repository of uchum. When uchum does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2007-05-23 19:57:37+05:00, gshchepa@stripped +9 -0 Fixed bug #27827. Actually there are 2 different bugs and bugfixes: 1. ON expressions was never included into CHECK OPTION checks for UPDATE and INSERT statements. 2. CHECK OPTION expression was checked over expired record buffers (with arbitrary data in the fields). The st_table_list::prep_check_option() function has been improved to include ON expression into check_option. The save_on_expr variable was used for saving of ON expressions for next executions of the query. Rowids of tables used in CHECK OPTION expression was added to temporary table rows. The multi_update::do_updates() method was improved to restore necessary record buffers before view_check_option() calculation. mysql-test/r/view.result@stripped, 2007-05-23 19:55:19+05:00, gshchepa@stripped +120 -0 Updated test case for bug #27827. mysql-test/t/view.test@stripped, 2007-05-23 19:51:03+05:00, gshchepa@stripped +93 -0 Updated test case for bug #27827. sql/item.cc@stripped, 2007-05-23 19:27:27+05:00, gshchepa@stripped +32 -0 Fixed bug #27827. The Item::collect_org_table_processor() virtual function added and overloaded in the Item_field class. sql/item.h@stripped, 2007-05-23 19:25:52+05:00, gshchepa@stripped +2 -0 Fixed bug #27827. The Item::collect_org_table_processor() virtual function added and overloaded in the Item_field class. sql/sql_class.h@stripped, 2007-05-23 19:29:30+05:00, gshchepa@stripped +11 -0 Fixed bug #27827. The multi_update::ref_keys_for_table variable has been added. sql/sql_select.cc@stripped, 2007-05-23 19:34:54+05:00, gshchepa@stripped +1 -0 The save_on_expr variable has been used to save ON expressions between EXECUTE calls. sql/sql_update.cc@stripped, 2007-05-23 19:35:59+05:00, gshchepa@stripped +124 -15 Fixed bug #27827. Rowids of tables used in CHECK OPTION expression was added to temporary table rows. The multi_update::do_updates() method was improved to restore necessary record buffers before view_check_option() calculation. sql/table.cc@stripped, 2007-05-23 19:34:16+05:00, gshchepa@stripped +31 -1 Fixed bug #27827. The st_table_list::prep_check_option() function has been improved to include ON expression into check_option. sql/table.h@stripped, 2007-05-23 19:32:52+05:00, gshchepa@stripped +10 -0 Fixed bug #27827. The save_on_expr variable has been added to save ON expressions between EXECUTE calls. # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: gshchepa # Host: gleb.loc # Root: /home/uchum/work/bk/mysql-5.0-opt-27827 --- 1.266/sql/item.cc 2007-05-04 19:56:50 +05:00 +++ 1.267/sql/item.cc 2007-05-23 19:27:27 +05:00 @@ -604,6 +604,38 @@ bool Item_field::collect_item_field_proc /* + Add this field table `map' to the output bitmask. + + SYNOPSIS + Item_field::collect_org_table_processor() + arg pointer to table_map + + DESCRIPTION + The method is used by Item::walk to collect all original (opposite to + result) table maps into single bitmask. + + IMPLEMENTATION + Item_cond::walk() and Item_func::walk() stop the evaluation of the + processor function for its arguments once the processor returns + true. Therefore in order to force this method being called for all item + arguments in a condition the method must return false. + + RETURN + FALSE to force the evaluation of collect_org_table_processor() + for the subsequent items. +*/ + +bool Item_field::collect_org_table_processor(byte *arg) +{ + DBUG_ENTER("Item_field::collect_org_table_processor"); + DBUG_PRINT("info", ("%s", field->field_name ? field->field_name : "noname")); + table_map *map= (table_map *) arg; + *map|= field->table->map; + DBUG_RETURN(FALSE); +} + + +/* Check if an Item_field references some field from a list of fields. SYNOPSIS --- 1.229/sql/item.h 2007-05-04 19:56:44 +05:00 +++ 1.230/sql/item.h 2007-05-23 19:25:52 +05:00 @@ -779,6 +779,7 @@ public: virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool cleanup_processor(byte *arg); virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool collect_org_table_processor(byte * arg) { return 0; } virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } virtual bool change_context_processor(byte *context) { return 0; } virtual bool reset_query_id_processor(byte *query_id_arg) { return 0; } @@ -1280,6 +1281,7 @@ public: void update_null_value(); Item *get_tmp_table_item(THD *thd); bool collect_item_field_processor(byte * arg); + virtual bool collect_org_table_processor(byte * arg); bool find_item_in_field_list_processor(byte *arg); bool reset_query_id_processor(byte *arg) { --- 1.329/sql/sql_class.h 2007-05-08 00:10:29 +05:00 +++ 1.330/sql/sql_class.h 2007-05-23 19:29:30 +05:00 @@ -2273,6 +2273,17 @@ class multi_update :public select_result List *fields, *values; List **fields_for_table, **values_for_table; uint table_count; + /* + ref_keys_for_table is a list of items describing + temporary table fields used to keep rowids of tables + necessary for view_check_option() calculation. + UPDATE of VIEW can update only one table, so only + one temporary table can be created, and only one list + of rowids is required. + For regular multi-update UPDATE statements this + list is empty. + */ + List ref_keys_for_table; Copy_field *copy_field; enum enum_duplicates handle_duplicates; bool do_update, trans_safe; --- 1.521/sql/sql_select.cc 2007-05-16 01:16:08 +05:00 +++ 1.522/sql/sql_select.cc 2007-05-23 19:34:54 +05:00 @@ -8147,6 +8147,7 @@ simplify_joins(JOIN *join, Liston_expr; + table->save_on_expr= table->on_expr; table->prep_on_expr= table->on_expr= 0; } } --- 1.217/sql/sql_update.cc 2007-05-12 00:18:46 +05:00 +++ 1.218/sql/sql_update.cc 2007-05-23 19:35:59 +05:00 @@ -1067,7 +1067,8 @@ int multi_update::prepare(List &no /* Allocate copy fields */ max_fields=0; for (i=0 ; i < table_count ; i++) - set_if_bigger(max_fields, fields_for_table[i]->elements); + set_if_bigger(max_fields, fields_for_table[i]->elements + + sizeof(table_map) * 8); // max. number of tables copy_field= new Copy_field[max_fields]; DBUG_RETURN(thd->is_fatal_error != 0); } @@ -1140,6 +1141,39 @@ static bool safe_update_on_fly(THD *thd, /* + Create Item_field to store rowid as string. + + SYNOPSIS + create_ref_key_field() + table Table to obtain rowid info. + field_name Name for the new field. + + RETURN + Newly allocated Item_field. +*/ + +static Item_field * +create_ref_key_field(TABLE *table, const char *field_name) +{ + Field_string *field= new Field_string(table->file->ref_length, 0, + field_name, + table, &my_charset_bin); + if (!field) + return NULL; + /* + The field will be converted to varstring when creating tmp table if + table to be updated was created by mysql 4.1. Deny this. + */ + field->can_alter_field_type= 0; + Item_field *ifield= new Item_field((Field *) field); + if (!ifield) + return NULL; + ifield->maybe_null= 0; + return ifield; +} + + +/* Initialize table for multi table IMPLEMENTATION @@ -1160,6 +1194,17 @@ multi_update::initialize_tables(JOIN *jo trans_safe= transactional_tables= main_table->file->has_transactions(); table_to_update= 0; + /* + UPDATE has at least one field&value pair, OTOH only one table fields may + be updated in the updatable VIEW. + For updatable VIEW the first_table_for_update variable is a saved pointer + to the single updatable table. For regular multi-UPDATE this variable + may points to an arbitrary updatable table. + */ + DBUG_ASSERT(fields->elements); + table_map first_table_for_update= + ((Item_field *) fields->head())->field->table->map; + /* Create a temporary table for keys to all tables, except main table */ for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local) { @@ -1181,6 +1226,25 @@ multi_update::initialize_tables(JOIN *jo } } + if (table->map == first_table_for_update && table_ref->check_option) + { + table_map map= 0; + table_ref->check_option->walk(&Item::collect_org_table_processor, + (byte*) &map); + map&= ~first_table_for_update; + for (TABLE_LIST *tbl_ref =leaves; + map && tbl_ref; + map&= ~tbl_ref->table->map, tbl_ref= tbl_ref->next_leaf) + { + TABLE *tbl= tbl_ref->table; + ifield= create_ref_key_field(tbl, tbl->alias); + if (!ifield) + DBUG_RETURN(1); + if (ref_keys_for_table.push_back(ifield)) + DBUG_RETURN(1); + } + } + TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt; /* @@ -1189,20 +1253,12 @@ multi_update::initialize_tables(JOIN *jo original row so that we can find and update it */ - /* ok to be on stack as this is not referenced outside of this func */ - Field_string offset(table->file->ref_length, 0, "offset", - table, &my_charset_bin); - /* - The field will be converted to varstring when creating tmp table if - table to be updated was created by mysql 4.1. Deny this. - */ - offset.can_alter_field_type= 0; - if (!(ifield= new Item_field(((Field *) &offset)))) - DBUG_RETURN(1); - ifield->maybe_null= 0; + ifield= create_ref_key_field(table, "offset"); if (temp_fields.push_front(ifield)) DBUG_RETURN(1); + temp_fields.concat(&ref_keys_for_table); + /* Make an unique key over the first field to avoid duplicated updates */ bzero((char*) &group, sizeof(group)); group.asc= 1; @@ -1350,10 +1406,31 @@ bool multi_update::send_data(List { int error; TABLE *tmp_table= tmp_tables[offset]; - fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1); /* Store pointer to row */ memcpy((char*) tmp_table->field[0]->ptr, (char*) table->file->ref, table->file->ref_length); + /* Store regular updated fields to row */ + List_iterator_fast values_it(*values_for_table[offset]); + uint field_num = 1; // skip already stored rowid of updated table + for (uint elements = fields_for_table[offset]->elements; + field_num <= elements; + field_num++) + { + Item *value= values_it++; + if (value->save_in_field(tmp_table->field[field_num], 0) == -1) + DBUG_RETURN(1); + } + /* For updatable VIEW: store rowids of tables used in CHECK OPTION */ + List_iterator_fast fi(ref_keys_for_table); + while (Item_field *field= (Item_field *) fi++) + { + TABLE *tbl= field->field->table; + tbl->file->position(tbl->record[0]); + memcpy((char*) tmp_table->field[field_num]->ptr, + (char*) tbl->file->ref, tbl->file->ref_length); + field_num++; + } + /* Write row, ignoring duplicated updates to a row */ error= tmp_table->file->write_row(tmp_table->record[0]); if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE) @@ -1406,6 +1483,7 @@ int multi_update::do_updates(bool from_s int local_error; ha_rows org_updated; TABLE *table, *tmp_table; + List_iterator_fast ref_keys_it(ref_keys_for_table); DBUG_ENTER("do_updates"); do_update= 0; // Don't retry this function @@ -1415,6 +1493,7 @@ int multi_update::do_updates(bool from_s { byte *ref_pos; bool can_compare_record; + uint offset= cur_table->shared; table = cur_table->table; if (table == table_to_update) @@ -1425,13 +1504,24 @@ int multi_update::do_updates(bool from_s (void) table->file->ha_rnd_init(0); table->file->extra(HA_EXTRA_NO_CACHE); + ref_keys_it.rewind(); + while (Item_field *item= (Item_field *) ref_keys_it++) + { + TABLE *tbl= item->field->table; + if (tbl->file->ha_rnd_init(1)) + goto err; + tbl->file->extra(HA_EXTRA_CACHE); + } + /* Setup copy functions to copy fields from temporary table */ - List_iterator_fast field_it(*fields_for_table[cur_table->shared]); + List_iterator_fast field_it(*fields_for_table[offset]); Field **field= tmp_table->field+1; // Skip row pointer Copy_field *copy_field_ptr= copy_field, *copy_field_end; - for ( ; *field ; field++) + for (uint i= 0, elements= fields_for_table[offset]->elements; + *field && i < elements; + field++, i++) { Item_field *item= (Item_field* ) field_it++; (copy_field_ptr++)->set(item->field, *field, 0); @@ -1468,6 +1558,18 @@ int multi_update::do_updates(bool from_s copy_field_ptr++) (*copy_field_ptr->do_copy)(copy_field_ptr); + ref_keys_it.rewind(); + Item_field *ifield; + for (uint fn= 1 + fields_for_table[offset]->elements; + (ifield= (Item_field *) ref_keys_it++); + fn++) + { + TABLE *tbl= ifield->field->table; + if((local_error= tbl->file->rnd_pos(tbl->record[0], + tmp_table->field[fn]->ptr))) + goto err; + } + if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)) @@ -1508,6 +1610,10 @@ int multi_update::do_updates(bool from_s } (void) table->file->ha_rnd_end(); (void) tmp_table->file->ha_rnd_end(); + ref_keys_it.rewind(); + while (Item_field *item= (Item_field *) ref_keys_it++) + item->field->table->file->ha_rnd_end(); + } DBUG_RETURN(0); @@ -1521,6 +1627,9 @@ err: err2: (void) table->file->ha_rnd_end(); (void) tmp_table->file->ha_rnd_end(); + ref_keys_it.rewind(); + while (Item_field *item= (Item_field *) ref_keys_it++) + item->field->table->file->ha_rnd_end(); if (updated != org_updated) { --- 1.250/sql/table.cc 2007-04-24 23:34:50 +05:00 +++ 1.251/sql/table.cc 2007-05-23 19:34:16 +05:00 @@ -2015,6 +2015,9 @@ bool st_table_list::prep_check_option(TH { DBUG_ENTER("st_table_list::prep_check_option"); + if (check_option) + DBUG_RETURN(FALSE); + for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { /* see comment of check_opt_type parameter */ @@ -2044,6 +2047,33 @@ bool st_table_list::prep_check_option(TH item= and_conds(item, tbl->check_option); } } + for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) + { + if (!tbl->join_list) + continue; + List_iterator li(*tbl->join_list); + while (TABLE_LIST *table= li++) + { + /* + The prep_check_option() function may be called either before + the simplify_joins() function or after simplify_joins() (from + the second call to EXECUTE). + The simplify_joins() sets save_on_expr and clears on_expr, + thus it is necessary to choose one of them. + */ + Item *on_expr= table->on_expr ? table->on_expr : table->save_on_expr; + if (on_expr) + { + /* + merge_underlying_list contains all underlying tables of this + VIEW (excluding tables used in subqueries), so we don't need + to walk through nested join tree recursively to collect all + required ON conditions for CHECK OPTION expression. + */ + item= and_conds(item, on_expr->copy_andor_structure(thd)); + } + } + } if (item) thd->change_item_tree(&check_option, item); } @@ -2150,7 +2180,7 @@ void st_table_list::cleanup_items() check CHECK OPTION condition SYNOPSIS - check_option() + st_table_list::view_check_option() ignore_failure ignore check option fail RETURN --- 1.141/sql/table.h 2007-03-31 15:36:46 +05:00 +++ 1.142/sql/table.h 2007-05-23 19:32:52 +05:00 @@ -481,6 +481,16 @@ typedef struct st_table_list char *db, *alias, *table_name, *schema_table_name; char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ + /* + Since the on_expr variable is zeroed for inner joins by the + simplify_joins() function, it is necessary to save a copy of + ON expression for the prep_check_option() function. + (prep_check_option() may be called during second EXECUTE call, + when on_expr and prep_on_expr are already NULLed). + Currently this field can be used only in the + st_table_list::prep_check_option() function. + */ + Item *save_on_expr; /* The structure of ON expression presented in the member above can be changed during certain optimizations. This member --- 1.200/mysql-test/r/view.result 2007-05-10 00:17:20 +05:00 +++ 1.201/mysql-test/r/view.result 2007-05-23 19:55:19 +05:00 @@ -3367,4 +3367,124 @@ SHOW CREATE VIEW v1; View Create View v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select cast(1.23456789 as decimal(8,0)) AS `col` DROP VIEW v1; +CREATE TABLE t1 (a1 INT); +CREATE TABLE t2 (a2 INT); +CREATE TABLE t3 (a3 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t3 VALUES (1),(2); +CREATE VIEW v1 AS SELECT t2.a2 AS a FROM t2 +JOIN t1 ON t1.a1=t2.a2 WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v1; +a +1 +2 +UPDATE v1 SET a=1; +ERROR HY000: CHECK OPTION failed 'test.v1' +UPDATE v1 SET a=3; +ERROR HY000: CHECK OPTION failed 'test.v1' +PREPARE t FROM 'UPDATE v1 SET a=3'; +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v1' +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v1' +INSERT INTO v1(a) VALUES (3); +ERROR HY000: CHECK OPTION failed 'test.v1' +UPDATE v1 SET a=1 WHERE a=1; +SELECT * FROM v1; +a +1 +2 +SELECT * FROM t1; +a1 +1 +2 +SELECT * FROM t2; +a2 +1 +2 +CREATE VIEW v2 AS SELECT t2.a2 AS a FROM t1 +JOIN t2 ON t1.a1=t2.a2 WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v2; +a +1 +2 +UPDATE v2 SET a=1; +ERROR HY000: CHECK OPTION failed 'test.v2' +UPDATE v2 SET a=3; +ERROR HY000: CHECK OPTION failed 'test.v2' +PREPARE t FROM 'UPDATE v2 SET a=3'; +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v2' +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v2' +INSERT INTO v2(a) VALUES (3); +ERROR HY000: CHECK OPTION failed 'test.v2' +UPDATE v2 SET a=1 WHERE a=1; +SELECT * FROM v2; +a +1 +2 +SELECT * FROM t1; +a1 +1 +2 +SELECT * FROM t2; +a2 +1 +2 +CREATE VIEW v3 AS SELECT t3.a3 AS a FROM t1 +JOIN (t2 JOIN t3 ON t2.a2=t3.a3) ON t1.a1=t2.a2 +WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v3; +a +1 +2 +UPDATE v3 SET a=1; +ERROR HY000: CHECK OPTION failed 'test.v3' +UPDATE v3 SET a=3; +ERROR HY000: CHECK OPTION failed 'test.v3' +PREPARE t FROM 'UPDATE v3 SET a=3'; +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v3' +EXECUTE t; +ERROR HY000: CHECK OPTION failed 'test.v3' +INSERT INTO v3(a) VALUES (3); +ERROR HY000: CHECK OPTION failed 'test.v3' +UPDATE v3 SET a=1 WHERE a=1; +SELECT * FROM v2; +a +1 +2 +SELECT * FROM t1; +a1 +1 +2 +SELECT * FROM t2; +a2 +1 +2 +SELECT * FROM t3; +a3 +1 +2 +DROP VIEW v1,v2,v3; +DROP TABLE t1,t2,t3; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT, c INT DEFAULT 0); +INSERT INTO t1 (a) VALUES (1), (2); +INSERT INTO t2 (b) VALUES (1), (2); +CREATE VIEW v1 AS SELECT t2.b,t2.c FROM t1, t2 +WHERE t1.a=t2.b AND t2.b < 3 WITH CHECK OPTION; +SELECT * FROM v1; +b c +1 0 +2 0 +UPDATE v1 SET c=1 WHERE b=1; +SELECT * FROM v1; +b c +1 1 +2 0 +DROP VIEW v1; +DROP TABLE t1,t2; End of 5.0 tests. --- 1.183/mysql-test/t/view.test 2007-05-10 00:17:20 +05:00 +++ 1.184/mysql-test/t/view.test 2007-05-23 19:51:03 +05:00 @@ -3233,4 +3233,97 @@ CREATE VIEW v1 AS SELECT CAST(1.23456789 SHOW CREATE VIEW v1; DROP VIEW v1; +# +# Bug #27827: CHECK OPTION ignores ON expressions during UPDATES and +# inserts, CHECK OPTION expression calculation over expired field +# data buffers. +# + +# Test case for ON condition: +CREATE TABLE t1 (a1 INT); +CREATE TABLE t2 (a2 INT); +CREATE TABLE t3 (a3 INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +INSERT INTO t3 VALUES (1),(2); + +# UPDATE without using of temporary tables: +CREATE VIEW v1 AS SELECT t2.a2 AS a FROM t2 + JOIN t1 ON t1.a1=t2.a2 WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v1; +--error 1369 +UPDATE v1 SET a=1; +--error 1369 +UPDATE v1 SET a=3; +PREPARE t FROM 'UPDATE v1 SET a=3'; +--error 1369 +EXECUTE t; +--error 1369 +EXECUTE t; +--error 1369 +INSERT INTO v1(a) VALUES (3); +UPDATE v1 SET a=1 WHERE a=1; +SELECT * FROM v1; +SELECT * FROM t1; +SELECT * FROM t2; + +# UPDATE via temporary table: +CREATE VIEW v2 AS SELECT t2.a2 AS a FROM t1 + JOIN t2 ON t1.a1=t2.a2 WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v2; +--error 1369 +UPDATE v2 SET a=1; +--error 1369 +UPDATE v2 SET a=3; +PREPARE t FROM 'UPDATE v2 SET a=3'; +--error 1369 +EXECUTE t; +--error 1369 +EXECUTE t; +--error 1369 +INSERT INTO v2(a) VALUES (3); +UPDATE v2 SET a=1 WHERE a=1; +SELECT * FROM v2; +SELECT * FROM t1; +SELECT * FROM t2; + +# Nesting joins: +CREATE VIEW v3 AS SELECT t3.a3 AS a FROM t1 + JOIN (t2 JOIN t3 ON t2.a2=t3.a3) ON t1.a1=t2.a2 + WHERE t2.a2 < 3 WITH CHECK OPTION; +SELECT * FROM v3; +--error 1369 +UPDATE v3 SET a=1; +--error 1369 +UPDATE v3 SET a=3; +PREPARE t FROM 'UPDATE v3 SET a=3'; +--error 1369 +EXECUTE t; +--error 1369 +EXECUTE t; +--error 1369 +INSERT INTO v3(a) VALUES (3); +UPDATE v3 SET a=1 WHERE a=1; + +SELECT * FROM v2; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP VIEW v1,v2,v3; +DROP TABLE t1,t2,t3; + +# Test case for calculation of CHECK OPTION expr. over expired buffers: +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT, c INT DEFAULT 0); +INSERT INTO t1 (a) VALUES (1), (2); +INSERT INTO t2 (b) VALUES (1), (2); +CREATE VIEW v1 AS SELECT t2.b,t2.c FROM t1, t2 + WHERE t1.a=t2.b AND t2.b < 3 WITH CHECK OPTION; +SELECT * FROM v1; +UPDATE v1 SET c=1 WHERE b=1; +SELECT * FROM v1; +DROP VIEW v1; +DROP TABLE t1,t2; + --echo End of 5.0 tests.