Merge gleb.loc:/home/uchum/work/bk/mysql-5.0-opt
into gleb.loc:/home/uchum/work/bk/mysql-5.0-opt-28716 sql/sql_class.h: Auto merged mysql-test/r/view.result: SCCS merged mysql-test/t/view.test: SCCS merged
This commit is contained in:
commit
a5c232a0e0
@ -3367,6 +3367,23 @@ SHOW CREATE VIEW v1;
|
|||||||
View Create View
|
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`
|
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;
|
DROP VIEW v1;
|
||||||
|
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;
|
||||||
CREATE TABLE t1 (id int);
|
CREATE TABLE t1 (id int);
|
||||||
CREATE TABLE t2 (id int, c int DEFAULT 0);
|
CREATE TABLE t2 (id int, c int DEFAULT 0);
|
||||||
INSERT INTO t1 (id) VALUES (1);
|
INSERT INTO t1 (id) VALUES (1);
|
||||||
|
@ -3233,6 +3233,22 @@ CREATE VIEW v1 AS SELECT CAST(1.23456789 AS DECIMAL(8,0)) AS col;
|
|||||||
SHOW CREATE VIEW v1;
|
SHOW CREATE VIEW v1;
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #28716: CHECK OPTION expression is evaluated over expired record buffers
|
||||||
|
# when VIEW is updated via temporary tables
|
||||||
|
#
|
||||||
|
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;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bug #28561: update on multi-table view with CHECK OPTION and
|
# Bug #28561: update on multi-table view with CHECK OPTION and
|
||||||
# a subquery in WHERE condition
|
# a subquery in WHERE condition
|
||||||
|
@ -2283,6 +2283,11 @@ class multi_update :public select_result_interceptor
|
|||||||
List <Item> *fields, *values;
|
List <Item> *fields, *values;
|
||||||
List <Item> **fields_for_table, **values_for_table;
|
List <Item> **fields_for_table, **values_for_table;
|
||||||
uint table_count;
|
uint table_count;
|
||||||
|
/*
|
||||||
|
List of tables referenced in the CHECK OPTION condition of
|
||||||
|
the updated view excluding the updated table.
|
||||||
|
*/
|
||||||
|
List <TABLE> unupdated_check_opt_tables;
|
||||||
Copy_field *copy_field;
|
Copy_field *copy_field;
|
||||||
enum enum_duplicates handle_duplicates;
|
enum enum_duplicates handle_duplicates;
|
||||||
bool do_update, trans_safe;
|
bool do_update, trans_safe;
|
||||||
|
@ -970,6 +970,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
List_iterator_fast<Item> field_it(*fields);
|
List_iterator_fast<Item> field_it(*fields);
|
||||||
List_iterator_fast<Item> value_it(*values);
|
List_iterator_fast<Item> value_it(*values);
|
||||||
uint i, max_fields;
|
uint i, max_fields;
|
||||||
|
uint leaf_table_count= 0;
|
||||||
DBUG_ENTER("multi_update::prepare");
|
DBUG_ENTER("multi_update::prepare");
|
||||||
|
|
||||||
thd->count_cuted_fields= CHECK_FIELD_WARN;
|
thd->count_cuted_fields= CHECK_FIELD_WARN;
|
||||||
@ -1003,6 +1004,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
{
|
{
|
||||||
/* TODO: add support of view of join support */
|
/* TODO: add support of view of join support */
|
||||||
TABLE *table=table_ref->table;
|
TABLE *table=table_ref->table;
|
||||||
|
leaf_table_count++;
|
||||||
if (tables_to_update & table->map)
|
if (tables_to_update & table->map)
|
||||||
{
|
{
|
||||||
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
|
TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
|
||||||
@ -1067,7 +1069,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
|||||||
/* Allocate copy fields */
|
/* Allocate copy fields */
|
||||||
max_fields=0;
|
max_fields=0;
|
||||||
for (i=0 ; i < table_count ; i++)
|
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 + leaf_table_count);
|
||||||
copy_field= new Copy_field[max_fields];
|
copy_field= new Copy_field[max_fields];
|
||||||
DBUG_RETURN(thd->is_fatal_error != 0);
|
DBUG_RETURN(thd->is_fatal_error != 0);
|
||||||
}
|
}
|
||||||
@ -1160,13 +1162,22 @@ multi_update::initialize_tables(JOIN *join)
|
|||||||
trans_safe= transactional_tables= main_table->file->has_transactions();
|
trans_safe= transactional_tables= main_table->file->has_transactions();
|
||||||
table_to_update= 0;
|
table_to_update= 0;
|
||||||
|
|
||||||
|
/* Any update has at least one pair (field, value) */
|
||||||
|
DBUG_ASSERT(fields->elements);
|
||||||
|
/*
|
||||||
|
Only one table may be modified by UPDATE of an updatable view.
|
||||||
|
For an updatable view first_table_for_update indicates this
|
||||||
|
table.
|
||||||
|
For a regular multi-update it refers to some updated table.
|
||||||
|
*/
|
||||||
|
TABLE *first_table_for_update= ((Item_field *) fields->head())->field->table;
|
||||||
|
|
||||||
/* Create a temporary table for keys to all tables, except main table */
|
/* 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)
|
for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
|
||||||
{
|
{
|
||||||
TABLE *table=table_ref->table;
|
TABLE *table=table_ref->table;
|
||||||
uint cnt= table_ref->shared;
|
uint cnt= table_ref->shared;
|
||||||
Item_field *ifield;
|
List<Item> temp_fields;
|
||||||
List<Item> temp_fields= *fields_for_table[cnt];
|
|
||||||
ORDER group;
|
ORDER group;
|
||||||
|
|
||||||
if (ignore)
|
if (ignore)
|
||||||
@ -1174,34 +1185,63 @@ multi_update::initialize_tables(JOIN *join)
|
|||||||
if (table == main_table) // First table in join
|
if (table == main_table) // First table in join
|
||||||
{
|
{
|
||||||
if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables,
|
if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables,
|
||||||
&temp_fields))
|
fields_for_table[cnt]))
|
||||||
{
|
{
|
||||||
table_to_update= main_table; // Update table on the fly
|
table_to_update= main_table; // Update table on the fly
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (table == first_table_for_update && table_ref->check_option)
|
||||||
|
{
|
||||||
|
table_map unupdated_tables= table_ref->check_option->used_tables() &
|
||||||
|
~first_table_for_update->map;
|
||||||
|
for (TABLE_LIST *tbl_ref =leaves;
|
||||||
|
unupdated_tables && tbl_ref;
|
||||||
|
tbl_ref= tbl_ref->next_leaf)
|
||||||
|
{
|
||||||
|
if (unupdated_tables & tbl_ref->table->map)
|
||||||
|
unupdated_tables&= ~tbl_ref->table->map;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
if (unupdated_check_opt_tables.push_back(tbl_ref->table))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
|
TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create a temporary table to store all fields that are changed for this
|
Create a temporary table to store all fields that are changed for this
|
||||||
table. The first field in the temporary table is a pointer to the
|
table. The first field in the temporary table is a pointer to the
|
||||||
original row so that we can find and update it
|
original row so that we can find and update it. For the updatable
|
||||||
|
VIEW a few following fields are rowids of tables used in the CHECK
|
||||||
|
OPTION condition.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ok to be on stack as this is not referenced outside of this func */
|
List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
|
||||||
Field_string offset(table->file->ref_length, 0, "offset",
|
TABLE *tbl= table;
|
||||||
table, &my_charset_bin);
|
do
|
||||||
/*
|
{
|
||||||
The field will be converted to varstring when creating tmp table if
|
Field_string *field= new Field_string(tbl->file->ref_length, 0,
|
||||||
table to be updated was created by mysql 4.1. Deny this.
|
tbl->alias,
|
||||||
*/
|
tbl, &my_charset_bin);
|
||||||
offset.can_alter_field_type= 0;
|
if (!field)
|
||||||
if (!(ifield= new Item_field(((Field *) &offset))))
|
DBUG_RETURN(1);
|
||||||
DBUG_RETURN(1);
|
/*
|
||||||
ifield->maybe_null= 0;
|
The field will be converted to varstring when creating tmp table if
|
||||||
if (temp_fields.push_front(ifield))
|
table to be updated was created by mysql 4.1. Deny this.
|
||||||
DBUG_RETURN(1);
|
*/
|
||||||
|
field->can_alter_field_type= 0;
|
||||||
|
Item_field *ifield= new Item_field((Field *) field);
|
||||||
|
if (!ifield)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
ifield->maybe_null= 0;
|
||||||
|
if (temp_fields.push_back(ifield))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
} while ((tbl= tbl_it++));
|
||||||
|
|
||||||
|
temp_fields.concat(fields_for_table[cnt]);
|
||||||
|
|
||||||
/* Make an unique key over the first field to avoid duplicated updates */
|
/* Make an unique key over the first field to avoid duplicated updates */
|
||||||
bzero((char*) &group, sizeof(group));
|
bzero((char*) &group, sizeof(group));
|
||||||
@ -1350,10 +1390,26 @@ bool multi_update::send_data(List<Item> ¬_used_values)
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
TABLE *tmp_table= tmp_tables[offset];
|
TABLE *tmp_table= tmp_tables[offset];
|
||||||
fill_record(thd, tmp_table->field+1, *values_for_table[offset], 1);
|
/* Store regular updated fields in the row. */
|
||||||
/* Store pointer to row */
|
fill_record(thd,
|
||||||
memcpy((char*) tmp_table->field[0]->ptr,
|
tmp_table->field + 1 + unupdated_check_opt_tables.elements,
|
||||||
(char*) table->file->ref, table->file->ref_length);
|
*values_for_table[offset], 1);
|
||||||
|
/*
|
||||||
|
For updatable VIEW store rowid of the updated table and
|
||||||
|
rowids of tables used in the CHECK OPTION condition.
|
||||||
|
*/
|
||||||
|
uint field_num= 0;
|
||||||
|
List_iterator_fast<TABLE> tbl_it(unupdated_check_opt_tables);
|
||||||
|
TABLE *tbl= table;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (tbl != 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++;
|
||||||
|
} while ((tbl= tbl_it++));
|
||||||
|
|
||||||
/* Write row, ignoring duplicated updates to a row */
|
/* Write row, ignoring duplicated updates to a row */
|
||||||
error= tmp_table->file->write_row(tmp_table->record[0]);
|
error= tmp_table->file->write_row(tmp_table->record[0]);
|
||||||
if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
|
if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
|
||||||
@ -1403,9 +1459,10 @@ void multi_update::send_error(uint errcode,const char *err)
|
|||||||
int multi_update::do_updates(bool from_send_error)
|
int multi_update::do_updates(bool from_send_error)
|
||||||
{
|
{
|
||||||
TABLE_LIST *cur_table;
|
TABLE_LIST *cur_table;
|
||||||
int local_error;
|
int local_error= 0;
|
||||||
ha_rows org_updated;
|
ha_rows org_updated;
|
||||||
TABLE *table, *tmp_table;
|
TABLE *table, *tmp_table;
|
||||||
|
List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables);
|
||||||
DBUG_ENTER("do_updates");
|
DBUG_ENTER("do_updates");
|
||||||
|
|
||||||
do_update= 0; // Don't retry this function
|
do_update= 0; // Don't retry this function
|
||||||
@ -1413,8 +1470,8 @@ int multi_update::do_updates(bool from_send_error)
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
|
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
|
||||||
{
|
{
|
||||||
byte *ref_pos;
|
|
||||||
bool can_compare_record;
|
bool can_compare_record;
|
||||||
|
uint offset= cur_table->shared;
|
||||||
|
|
||||||
table = cur_table->table;
|
table = cur_table->table;
|
||||||
if (table == table_to_update)
|
if (table == table_to_update)
|
||||||
@ -1425,11 +1482,20 @@ int multi_update::do_updates(bool from_send_error)
|
|||||||
(void) table->file->ha_rnd_init(0);
|
(void) table->file->ha_rnd_init(0);
|
||||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||||
|
|
||||||
|
check_opt_it.rewind();
|
||||||
|
while(TABLE *tbl= check_opt_it++)
|
||||||
|
{
|
||||||
|
if (tbl->file->ha_rnd_init(1))
|
||||||
|
goto err;
|
||||||
|
tbl->file->extra(HA_EXTRA_CACHE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup copy functions to copy fields from temporary table
|
Setup copy functions to copy fields from temporary table
|
||||||
*/
|
*/
|
||||||
List_iterator_fast<Item> field_it(*fields_for_table[cur_table->shared]);
|
List_iterator_fast<Item> field_it(*fields_for_table[offset]);
|
||||||
Field **field= tmp_table->field+1; // Skip row pointer
|
Field **field= tmp_table->field +
|
||||||
|
1 + unupdated_check_opt_tables.elements; // Skip row pointers
|
||||||
Copy_field *copy_field_ptr= copy_field, *copy_field_end;
|
Copy_field *copy_field_ptr= copy_field, *copy_field_end;
|
||||||
for ( ; *field ; field++)
|
for ( ; *field ; field++)
|
||||||
{
|
{
|
||||||
@ -1444,7 +1510,6 @@ int multi_update::do_updates(bool from_send_error)
|
|||||||
can_compare_record= !(table->file->table_flags() &
|
can_compare_record= !(table->file->table_flags() &
|
||||||
HA_PARTIAL_COLUMN_READ);
|
HA_PARTIAL_COLUMN_READ);
|
||||||
|
|
||||||
ref_pos= (byte*) tmp_table->field[0]->ptr;
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (thd->killed && trans_safe)
|
if (thd->killed && trans_safe)
|
||||||
@ -1457,8 +1522,19 @@ int multi_update::do_updates(bool from_send_error)
|
|||||||
continue; // May happen on dup key
|
continue; // May happen on dup key
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
|
|
||||||
goto err;
|
/* call rnd_pos() using rowids from temporary table */
|
||||||
|
check_opt_it.rewind();
|
||||||
|
TABLE *tbl= table;
|
||||||
|
uint field_num= 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if((local_error= tbl->file->rnd_pos(tbl->record[0],
|
||||||
|
tmp_table->field[field_num]->ptr)))
|
||||||
|
goto err;
|
||||||
|
field_num++;
|
||||||
|
} while((tbl= check_opt_it++));
|
||||||
|
|
||||||
table->status|= STATUS_UPDATED;
|
table->status|= STATUS_UPDATED;
|
||||||
store_record(table,record[1]);
|
store_record(table,record[1]);
|
||||||
|
|
||||||
@ -1508,6 +1584,10 @@ int multi_update::do_updates(bool from_send_error)
|
|||||||
}
|
}
|
||||||
(void) table->file->ha_rnd_end();
|
(void) table->file->ha_rnd_end();
|
||||||
(void) tmp_table->file->ha_rnd_end();
|
(void) tmp_table->file->ha_rnd_end();
|
||||||
|
check_opt_it.rewind();
|
||||||
|
while (TABLE *tbl= check_opt_it++)
|
||||||
|
tbl->file->ha_rnd_end();
|
||||||
|
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
@ -1521,6 +1601,9 @@ err:
|
|||||||
err2:
|
err2:
|
||||||
(void) table->file->ha_rnd_end();
|
(void) table->file->ha_rnd_end();
|
||||||
(void) tmp_table->file->ha_rnd_end();
|
(void) tmp_table->file->ha_rnd_end();
|
||||||
|
check_opt_it.rewind();
|
||||||
|
while (TABLE *tbl= check_opt_it++)
|
||||||
|
tbl->file->ha_rnd_end();
|
||||||
|
|
||||||
if (updated != org_updated)
|
if (updated != org_updated)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user