mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
support of join view updateability (WL#1809)
include/mysqld_error.h: new error mesaages mysql-test/r/view.result: tests of updatint/inserting join views mysql-test/t/view.test: tests of updatint/inserting join views sql/mysql_priv.h: support of "usual UPDATE" -> "multi UPDATE" conversion sql/share/czech/errmsg.txt: new error mesaages sql/share/danish/errmsg.txt: new error mesaages sql/share/dutch/errmsg.txt: new error mesaages sql/share/english/errmsg.txt: new error mesaages sql/share/estonian/errmsg.txt: new error mesaages sql/share/french/errmsg.txt: new error mesaages sql/share/german/errmsg.txt: new error mesaages sql/share/greek/errmsg.txt: new error mesaages sql/share/hungarian/errmsg.txt: new error mesaages sql/share/italian/errmsg.txt: new error mesaages sql/share/japanese/errmsg.txt: new error mesaages sql/share/korean/errmsg.txt: new error mesaages sql/share/norwegian-ny/errmsg.txt: new error mesaages sql/share/norwegian/errmsg.txt: new error mesaages sql/share/polish/errmsg.txt: new error mesaages sql/share/portuguese/errmsg.txt: new error mesaages sql/share/romanian/errmsg.txt: new error mesaages sql/share/russian/errmsg.txt: new error mesaages sql/share/serbian/errmsg.txt: new error mesaages sql/share/slovak/errmsg.txt: new error mesaages sql/share/spanish/errmsg.txt: new error mesaages sql/share/swedish/errmsg.txt: new error mesaages sql/share/ukrainian/errmsg.txt: new error mesaages sql/sql_base.cc: test to avoid join virew to be catched here sql/sql_class.h: support of join views add to update sql/sql_delete.cc: support of join views add to delete(error issue) sql/sql_insert.cc: support of join views add to insert (order of some check changed, to allow find table which will be inserted in, when we will know which fields will be inserted) mechanism of calling setup_tables() only once fixed for INSERT SELECT sql/sql_parse.cc: support of "usual UPDATE" -> "multi UPDATE" conversion mysql_insert_select_prepare now called in same environment for usual queries and PS preparing support of join views add to delete (error issue) sql/sql_prepare.cc: support of "usual UPDATE" -> "multi UPDATE" conversion support of join views add to delete (error issue) sql/sql_update.cc: support of join views add to update sql/sql_view.cc: join views made updatable sql/sql_view.h: insert_view_fields now can check some errors sql/table.cc: methods to support recursive walk by tables tree sql/table.h: methods to support recursive walk by tables tree
This commit is contained in:
@ -380,4 +380,7 @@
|
||||
#define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361
|
||||
#define ER_TRG_CANT_CHANGE_ROW 1362
|
||||
#define ER_TRG_NO_SUCH_ROW_IN_TRG 1363
|
||||
#define ER_ERROR_MESSAGES 364
|
||||
#define ER_VIEW_MULTIUPDATE 1364
|
||||
#define ER_VIEW_NO_INSERT_FIELD_LIST 1365
|
||||
#define ER_VIEW_DELETE_MERGE_VIEW 1366
|
||||
#define ER_ERROR_MESSAGES 367
|
||||
|
@ -1359,3 +1359,152 @@ a a b
|
||||
deallocate prepare stmt1;
|
||||
drop view v4,v3,v2,v1;
|
||||
drop tables t1,t2,t3;
|
||||
create table t1 (a int, primary key (a), b int);
|
||||
create table t2 (a int, primary key (a));
|
||||
insert into t1 values (1,100), (2,200);
|
||||
insert into t2 values (1), (3);
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
|
||||
update v3 set a= 10 where a=1;
|
||||
select * from t1;
|
||||
a b
|
||||
10 100
|
||||
2 200
|
||||
select * from t2;
|
||||
a
|
||||
1
|
||||
3
|
||||
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
|
||||
update v2 set a= 10 where a=200;
|
||||
ERROR HY000: The target table v2 of the UPDATE is not updatable
|
||||
select * from v3;
|
||||
a b
|
||||
2 1
|
||||
10 1
|
||||
2 3
|
||||
10 3
|
||||
select * from v2;
|
||||
a b
|
||||
100 1
|
||||
200 1
|
||||
100 3
|
||||
200 3
|
||||
set @a= 10;
|
||||
set @b= 100;
|
||||
prepare stmt1 from "update v3 set a= ? where a=?";
|
||||
execute stmt1 using @a,@b;
|
||||
select * from v3;
|
||||
a b
|
||||
2 1
|
||||
10 1
|
||||
2 3
|
||||
10 3
|
||||
set @a= 300;
|
||||
set @b= 10;
|
||||
execute stmt1 using @a,@b;
|
||||
select * from v3;
|
||||
a b
|
||||
2 1
|
||||
300 1
|
||||
2 3
|
||||
300 3
|
||||
deallocate prepare stmt1;
|
||||
drop view v3,v2;
|
||||
drop tables t1,t2;
|
||||
create table t1 (a int, primary key (a), b int);
|
||||
create table t2 (a int, primary key (a), b int);
|
||||
insert into t2 values (1000, 2000);
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
|
||||
insert into v3 values (1,2);
|
||||
ERROR HY000: Can not insert into join view 'test.v3' without fields list
|
||||
insert into v3 select * from t2;
|
||||
ERROR HY000: Can not insert into join view 'test.v3' without fields list
|
||||
insert into v3(a,b) values (1,2);
|
||||
ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
|
||||
insert into v3(a,b) select * from t2;
|
||||
ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
|
||||
insert into v3(a) values (1);
|
||||
insert into v3(b) values (10);
|
||||
insert into v3(a) select a from t2;
|
||||
insert into v3(b) select b from t2;
|
||||
Warnings:
|
||||
Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 2
|
||||
insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
|
||||
select * from t1;
|
||||
a b
|
||||
10002 NULL
|
||||
10 NULL
|
||||
1000 NULL
|
||||
select * from t2;
|
||||
a b
|
||||
1000 2000
|
||||
10 NULL
|
||||
2000 NULL
|
||||
0 NULL
|
||||
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
|
||||
insert into v2(a) values (10);
|
||||
ERROR HY000: The target table v2 of the INSERT is not updatable
|
||||
select * from v3;
|
||||
a b
|
||||
10 1000
|
||||
1000 1000
|
||||
10002 1000
|
||||
10 10
|
||||
1000 10
|
||||
10002 10
|
||||
10 2000
|
||||
1000 2000
|
||||
10002 2000
|
||||
10 0
|
||||
1000 0
|
||||
10002 0
|
||||
select * from v2;
|
||||
a b
|
||||
NULL 1000
|
||||
NULL 1000
|
||||
NULL 1000
|
||||
NULL 10
|
||||
NULL 10
|
||||
NULL 10
|
||||
NULL 2000
|
||||
NULL 2000
|
||||
NULL 2000
|
||||
NULL 0
|
||||
NULL 0
|
||||
NULL 0
|
||||
delete from v3;
|
||||
ERROR HY000: Can not delete from join view 'test.v3'
|
||||
delete v3,t1 from v3,t1;
|
||||
ERROR HY000: Can not delete from join view 'test.v3'
|
||||
delete from t1;
|
||||
prepare stmt1 from "insert into v3(a) values (?);";
|
||||
set @a= 100;
|
||||
execute stmt1 using @a;
|
||||
set @a= 300;
|
||||
execute stmt1 using @a;
|
||||
deallocate prepare stmt1;
|
||||
prepare stmt1 from "insert into v3(a) select ?;";
|
||||
set @a= 101;
|
||||
execute stmt1 using @a;
|
||||
set @a= 301;
|
||||
execute stmt1 using @a;
|
||||
deallocate prepare stmt1;
|
||||
select * from v3;
|
||||
a b
|
||||
100 1000
|
||||
101 1000
|
||||
300 1000
|
||||
301 1000
|
||||
100 10
|
||||
101 10
|
||||
300 10
|
||||
301 10
|
||||
100 2000
|
||||
101 2000
|
||||
300 2000
|
||||
301 2000
|
||||
100 0
|
||||
101 0
|
||||
300 0
|
||||
301 0
|
||||
drop view v3,v2;
|
||||
drop tables t1,t2;
|
||||
|
@ -1298,3 +1298,93 @@ execute stmt1;
|
||||
deallocate prepare stmt1;
|
||||
drop view v4,v3,v2,v1;
|
||||
drop tables t1,t2,t3;
|
||||
|
||||
#
|
||||
# updating of join view
|
||||
#
|
||||
create table t1 (a int, primary key (a), b int);
|
||||
create table t2 (a int, primary key (a));
|
||||
insert into t1 values (1,100), (2,200);
|
||||
insert into t2 values (1), (3);
|
||||
# legal view for update
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
|
||||
update v3 set a= 10 where a=1;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
# view without primary key
|
||||
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
|
||||
-- error 1288
|
||||
update v2 set a= 10 where a=200;
|
||||
# just view selects
|
||||
select * from v3;
|
||||
select * from v2;
|
||||
# prepare statement with updating join view
|
||||
set @a= 10;
|
||||
set @b= 100;
|
||||
prepare stmt1 from "update v3 set a= ? where a=?";
|
||||
execute stmt1 using @a,@b;
|
||||
select * from v3;
|
||||
set @a= 300;
|
||||
set @b= 10;
|
||||
execute stmt1 using @a,@b;
|
||||
select * from v3;
|
||||
deallocate prepare stmt1;
|
||||
drop view v3,v2;
|
||||
drop tables t1,t2;
|
||||
|
||||
#
|
||||
# inserting/deleting join view
|
||||
#
|
||||
create table t1 (a int, primary key (a), b int);
|
||||
create table t2 (a int, primary key (a), b int);
|
||||
insert into t2 values (1000, 2000);
|
||||
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
|
||||
# inserting into join view without field list
|
||||
-- error 1365
|
||||
insert into v3 values (1,2);
|
||||
-- error 1365
|
||||
insert into v3 select * from t2;
|
||||
# inserting in several tables of join view
|
||||
-- error 1364
|
||||
insert into v3(a,b) values (1,2);
|
||||
-- error 1364
|
||||
insert into v3(a,b) select * from t2;
|
||||
# correct inserts into join view
|
||||
insert into v3(a) values (1);
|
||||
insert into v3(b) values (10);
|
||||
insert into v3(a) select a from t2;
|
||||
insert into v3(b) select b from t2;
|
||||
insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
# view without primary key
|
||||
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
|
||||
-- error 1288
|
||||
insert into v2(a) values (10);
|
||||
# just view selects
|
||||
select * from v3;
|
||||
select * from v2;
|
||||
# try delete from join view
|
||||
-- error 1366
|
||||
delete from v3;
|
||||
-- error 1366
|
||||
delete v3,t1 from v3,t1;
|
||||
# delete from t1 just to reduce result set size
|
||||
delete from t1;
|
||||
# prepare statement with insert join view
|
||||
prepare stmt1 from "insert into v3(a) values (?);";
|
||||
set @a= 100;
|
||||
execute stmt1 using @a;
|
||||
set @a= 300;
|
||||
execute stmt1 using @a;
|
||||
deallocate prepare stmt1;
|
||||
prepare stmt1 from "insert into v3(a) select ?;";
|
||||
set @a= 101;
|
||||
execute stmt1 using @a;
|
||||
set @a= 301;
|
||||
execute stmt1 using @a;
|
||||
deallocate prepare stmt1;
|
||||
select * from v3;
|
||||
|
||||
drop view v3,v2;
|
||||
drop tables t1,t2;
|
||||
|
@ -611,7 +611,8 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> *fields, List<Item> *values,
|
||||
COND *conds, ulong options,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
|
||||
bool converted);
|
||||
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
List<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields,
|
||||
|
@ -392,3 +392,6 @@ character-set=latin2
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -383,3 +383,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -392,3 +392,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -385,3 +385,6 @@ character-set=latin7
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -393,3 +393,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=greek
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -385,3 +385,6 @@ character-set=latin2
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -384,3 +384,6 @@ character-set=ujis
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=euckr
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -382,3 +382,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -382,3 +382,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -385,3 +385,6 @@ character-set=latin2
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -382,3 +382,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -385,3 +385,6 @@ character-set=latin2
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -376,7 +376,7 @@ character-set=koi8r
|
||||
"View SELECT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
|
||||
"View SELECT <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> view <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>)"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><>) <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>)"
|
||||
"View '%-.64s.%-.64s' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
"Can't drop a %s from within another stored routine"
|
||||
"GOTO is not allowed in a stored procedure handler"
|
||||
@ -385,3 +385,6 @@ character-set=koi8r
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s'"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s' <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s'"
|
||||
|
@ -373,3 +373,6 @@ character-set=cp1250
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -388,3 +388,6 @@ character-set=latin2
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -384,3 +384,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=latin1
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
|
||||
"Can not insert into join view '%-.64s.%-.64s' without fields list"
|
||||
"Can not delete from join view '%-.64s.%-.64s'"
|
||||
|
@ -386,3 +386,6 @@ character-set=koi8u
|
||||
"Trigger's '%-.64s' is view or temporary table"
|
||||
"Updating of %s row is not allowed in %strigger"
|
||||
"There is no %s row in %s trigger"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ¦<><C2A6><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s', <20><> ͦ<>Ԧ<EFBFBD><D4A6> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> VIEW '%-.64s.%-.64s', <20><> ͦ<><CDA6><EFBFBD><EFBFBD><EFBFBD> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>æ<EFBFBD>"
|
||||
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> VIEW '%-.64s.%-.64s', <20><> ͦ<><CDA6><EFBFBD><EFBFBD><EFBFBD> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||
|
@ -2296,7 +2296,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
bool allow_rowid= tables && !tables->next_local; // Only one table
|
||||
for (; tables ; tables= tables->next_local)
|
||||
{
|
||||
if (!tables->table)
|
||||
if (!tables->table && !tables->ancestor)
|
||||
{
|
||||
if (report_error)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||
|
@ -1504,7 +1504,9 @@ public:
|
||||
|
||||
class multi_update :public select_result
|
||||
{
|
||||
TABLE_LIST *all_tables, *update_tables, *table_being_updated;
|
||||
TABLE_LIST *all_tables; /* query/update command tables */
|
||||
TABLE_LIST *leaves; /* list of leves of join table tree */
|
||||
TABLE_LIST *update_tables, *table_being_updated;
|
||||
THD *thd;
|
||||
TABLE **tmp_tables, *main_table, *table_to_update;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
@ -1517,8 +1519,9 @@ class multi_update :public select_result
|
||||
bool do_update, trans_safe, transactional_tables, log_delayed;
|
||||
|
||||
public:
|
||||
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
|
||||
List<Item> *values, enum_duplicates handle_duplicates);
|
||||
multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,
|
||||
List<Item> *fields, List<Item> *values,
|
||||
enum_duplicates handle_duplicates);
|
||||
~multi_update();
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_fields(List<Item> &list, uint flags) { return 0; }
|
||||
|
@ -43,7 +43,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
|
||||
|
||||
if ((error= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(error);
|
||||
table= table_list->table;
|
||||
if (!(table= table_list->table))
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||
table_list->view_db.str, table_list->view_name.str);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
thd->proc_info="init";
|
||||
table->map=1;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "sql_acl.h"
|
||||
#include "sp_head.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
static int check_null_fields(THD *thd,TABLE *entry);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -31,6 +32,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, ulong query_id);
|
||||
|
||||
/* Define to force use of my_malloc() if the allocated memory block is big */
|
||||
|
||||
@ -54,8 +56,22 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
{
|
||||
TABLE *table= table_list->table;
|
||||
|
||||
if (!table_list->updatable)
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fields.elements == 0 && values.elements != 0)
|
||||
{
|
||||
if (!table)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
|
||||
table_list->view_db.str, table_list->view_name.str);
|
||||
return -1;
|
||||
}
|
||||
if (values.elements != table->fields)
|
||||
{
|
||||
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||
@ -97,6 +113,23 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
thd->lex->select_lex.no_wrap_view_item= 0;
|
||||
if (res)
|
||||
return -1;
|
||||
if (table == 0)
|
||||
{
|
||||
/* it is join view => we need to find table for update */
|
||||
List_iterator_fast<Item> it(fields);
|
||||
Item *item;
|
||||
TABLE_LIST *tbl= 0;
|
||||
table_map map= 0;
|
||||
while (item= it++)
|
||||
map|= item->used_tables();
|
||||
if (table_list->check_single_table(&tbl, map) || tbl == 0)
|
||||
{
|
||||
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
|
||||
table_list->view_db.str, table_list->view_name.str);
|
||||
return -1;
|
||||
}
|
||||
table_list->table= table= tbl->table;
|
||||
}
|
||||
|
||||
if (check_unique && thd->dupp_field)
|
||||
{
|
||||
@ -111,6 +144,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
|
||||
#endif
|
||||
|
||||
if (check_key_in_view(thd, table_list) ||
|
||||
(table_list->view &&
|
||||
check_view_insertability(table_list, thd->query_id)))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -134,7 +176,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
ulong counter = 1;
|
||||
ulonglong id;
|
||||
COPY_INFO info;
|
||||
TABLE *table;
|
||||
TABLE *table= 0;
|
||||
List_iterator_fast<List_item> its(values_list);
|
||||
List_item *values;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -201,17 +243,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
if (res || thd->is_fatal_error)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
table= table_list->table;
|
||||
thd->proc_info="init";
|
||||
thd->used_tables=0;
|
||||
values= its++;
|
||||
|
||||
if (duplic == DUP_UPDATE && !table->insert_values)
|
||||
if (duplic == DUP_UPDATE)
|
||||
{
|
||||
/* it should be allocated before Item::fix_fields() */
|
||||
table->insert_values=
|
||||
(byte *)alloc_root(&thd->mem_root, table->rec_buff_length);
|
||||
if (!table->insert_values)
|
||||
if (table_list->set_insert_values(&thd->mem_root))
|
||||
goto abort;
|
||||
}
|
||||
|
||||
@ -219,6 +258,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
update_fields, update_values, duplic))
|
||||
goto abort;
|
||||
|
||||
/* 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
|
||||
value_count= values->elements;
|
||||
while ((values= its++))
|
||||
@ -437,7 +479,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
::send_ok(thd, (ulong) thd->row_count_func, id, buff);
|
||||
}
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
table_list->clear_insert_values();
|
||||
DBUG_RETURN(0);
|
||||
|
||||
abort:
|
||||
@ -446,7 +488,7 @@ abort:
|
||||
end_delayed_insert(thd);
|
||||
#endif
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
table_list->clear_insert_values();
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
@ -542,11 +584,12 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
where Pointer to where clause
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 ERROR
|
||||
0 ok
|
||||
1 ERROR and message sent to client
|
||||
-1 ERROR but message is not sent to client
|
||||
*/
|
||||
|
||||
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> &fields, COND **where)
|
||||
{
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
@ -554,22 +597,22 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
|
||||
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
|
||||
0))
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(thd->net.report_error ? -1 : 1);
|
||||
|
||||
if (insert_into_view && !fields.elements)
|
||||
{
|
||||
thd->lex->empty_field_list_on_rset= 1;
|
||||
insert_view_fields(&fields, table_list);
|
||||
if (!table_list->table)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
|
||||
table_list->view_db.str, table_list->view_name.str);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(insert_view_fields(&fields, table_list));
|
||||
}
|
||||
|
||||
if (!table_list->updatable ||
|
||||
check_key_in_view(thd, table_list) ||
|
||||
(insert_into_view &&
|
||||
check_view_insertability(table_list, thd->query_id)))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -598,8 +641,9 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
int res;
|
||||
DBUG_ENTER("mysql_prepare_insert");
|
||||
|
||||
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
|
||||
DBUG_RETURN(-1);
|
||||
if ((res= mysql_prepare_insert_check_table(thd, table_list,
|
||||
fields, &unused_conds)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
if (check_insert_fields(thd, table_list, fields, *values, 1,
|
||||
!insert_into_view) ||
|
||||
@ -1607,21 +1651,43 @@ bool delayed_insert::handle_inserts(void)
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
-1 Error
|
||||
1 Error sent to client
|
||||
-1 Error is not sent to client
|
||||
*/
|
||||
|
||||
int mysql_insert_select_prepare(THD *thd)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE_LIST* first_select_table=
|
||||
(TABLE_LIST*)lex->select_lex.table_list.first;
|
||||
TABLE_LIST* first_select_leaf_table;
|
||||
int res;
|
||||
DBUG_ENTER("mysql_insert_select_prepare");
|
||||
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
lex->field_list,
|
||||
&lex->select_lex.where))
|
||||
DBUG_RETURN(-1);
|
||||
/* exclude first table from leaf tables list, because it belong to INSERT */
|
||||
if ((res= mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
lex->field_list,
|
||||
&lex->select_lex.where)))
|
||||
DBUG_RETURN(res);
|
||||
/*
|
||||
setup was done in mysql_insert_select_prepare, but we have to mark
|
||||
first local table
|
||||
*/
|
||||
if (first_select_table)
|
||||
first_select_table->setup_is_done= 1;
|
||||
/*
|
||||
exclude first table from leaf tables list, because it belong to
|
||||
INSERT
|
||||
*/
|
||||
DBUG_ASSERT(lex->select_lex.leaf_tables);
|
||||
lex->leaf_tables_insert= lex->select_lex.leaf_tables;
|
||||
lex->select_lex.leaf_tables= lex->select_lex.leaf_tables->next_leaf;
|
||||
/* skip all leaf tables belonged to view where we are insert */
|
||||
for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf;
|
||||
first_select_leaf_table &&
|
||||
first_select_leaf_table->belong_to_view &&
|
||||
first_select_leaf_table->belong_to_view ==
|
||||
lex->leaf_tables_insert->belong_to_view;
|
||||
first_select_leaf_table= first_select_leaf_table->next_leaf)
|
||||
{}
|
||||
lex->select_lex.leaf_tables= first_select_leaf_table;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -1635,6 +1701,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
if (check_insert_fields(thd, table_list, *fields, values, 1,
|
||||
!insert_into_view))
|
||||
DBUG_RETURN(1);
|
||||
/*
|
||||
if it is INSERT into join view then check_insert_fields already found
|
||||
real table for insert
|
||||
*/
|
||||
table= table_list->table;
|
||||
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts of
|
||||
query
|
||||
*/
|
||||
if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) &&
|
||||
unique_table(table_list, table_list->next_independent()))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
thd->lex->current_select->options|= OPTION_BUFFER_RESULT;
|
||||
thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
|
||||
restore_record(table,default_values); // Get empty record
|
||||
table->next_number_field=table->found_next_number_field;
|
||||
|
@ -2747,18 +2747,29 @@ unsent_create_error:
|
||||
lex->duplicates);
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
break;
|
||||
if (res != 2)
|
||||
break;
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
{
|
||||
bool converted= 0;
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if ((res= multi_update_precheck(thd, all_tables)))
|
||||
break;
|
||||
if (res != 2)
|
||||
{
|
||||
if ((res= multi_update_precheck(thd, all_tables)))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
res= 0;
|
||||
converted= 1;
|
||||
}
|
||||
res= mysql_multi_update(thd, all_tables,
|
||||
&select_lex->item_list,
|
||||
&lex->value_list,
|
||||
select_lex->where,
|
||||
select_lex->options,
|
||||
lex->duplicates, unit, select_lex);
|
||||
lex->duplicates, unit, select_lex,
|
||||
converted);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REPLACE:
|
||||
@ -2796,31 +2807,26 @@ unsent_create_error:
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables)))
|
||||
{
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts of
|
||||
query
|
||||
*/
|
||||
if (unique_table(first_table, all_tables->next_independent()))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
select_lex->options |= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*)first_table->next_local;
|
||||
|
||||
res= mysql_insert_select_prepare(thd);
|
||||
if (!res && (result= new select_insert(first_table, first_table->table,
|
||||
&lex->field_list,
|
||||
lex->duplicates)))
|
||||
{
|
||||
TABLE_LIST *first_select_table;
|
||||
|
||||
if ((res= mysql_insert_select_prepare(thd)))
|
||||
break;
|
||||
if ((result= new select_insert(first_table, first_table->table,
|
||||
&lex->field_list, lex->duplicates)))
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*) first_table->next_local;
|
||||
/*
|
||||
insert/replace from SELECT give its SELECT_LEX for SELECT,
|
||||
and item_list belong to SELECT
|
||||
*/
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
|
||||
res= handle_select(thd, lex, result);
|
||||
/* revert changes for SP */
|
||||
lex->select_lex.table_list.first= (byte*) first_table;
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||
}
|
||||
/* revert changes for SP */
|
||||
lex->select_lex.table_list.first= (byte*) first_table;
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
}
|
||||
@ -2884,6 +2890,16 @@ unsent_create_error:
|
||||
if ((res= open_and_lock_tables(thd, all_tables)))
|
||||
break;
|
||||
|
||||
if (!first_table->table)
|
||||
{
|
||||
DBUG_ASSERT(first_table->view &&
|
||||
first_table->ancestor && first_table->ancestor->next_local);
|
||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||
first_table->view_db.str, first_table->view_name.str);
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((res= mysql_multi_delete_prepare(thd)))
|
||||
break;
|
||||
|
||||
|
@ -959,6 +959,7 @@ error:
|
||||
|
||||
RETURN VALUE
|
||||
0 success
|
||||
2 convert to multi_update
|
||||
1 error, sent to client
|
||||
-1 error, not sent to client
|
||||
*/
|
||||
@ -975,6 +976,15 @@ static int mysql_test_update(Prepared_statement *stmt,
|
||||
|
||||
if (!(res=open_and_lock_tables(thd, table_list)))
|
||||
{
|
||||
if (table_list->table == 0)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
stmt->lex->sql_command= SQLCOM_UPDATE_MULTI;
|
||||
DBUG_PRINT("info", ("Switch to multi-update (command replaced)"));
|
||||
/* convert to multiupdate */
|
||||
return 2;
|
||||
}
|
||||
if (!(res= mysql_prepare_update(thd, table_list,
|
||||
&select->where,
|
||||
select->order_list.elements,
|
||||
@ -1027,6 +1037,15 @@ static int mysql_test_delete(Prepared_statement *stmt,
|
||||
|
||||
if (!(res=open_and_lock_tables(thd, table_list)))
|
||||
{
|
||||
if (!table_list->table)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||
table_list->view_db.str, table_list->view_name.str);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
|
||||
lex->unit.cleanup();
|
||||
}
|
||||
@ -1219,7 +1238,10 @@ static int select_like_statement_test(Prepared_statement *stmt,
|
||||
LEX *lex= stmt->lex;
|
||||
int res= 0;
|
||||
|
||||
if (tables && (res= open_and_lock_tables(thd, tables)))
|
||||
/* check that tables was not opened during conversion from usual update */
|
||||
if (tables &&
|
||||
(!tables->table && !tables->view) &&
|
||||
(res= open_and_lock_tables(thd, tables)))
|
||||
goto end;
|
||||
|
||||
if (specific_prepare && (res= (*specific_prepare)(thd)))
|
||||
@ -1285,6 +1307,7 @@ static int mysql_test_create_table(Prepared_statement *stmt)
|
||||
mysql_test_multiupdate()
|
||||
stmt prepared statemen handler
|
||||
tables list of tables queries
|
||||
converted converted to multi-update from usual update
|
||||
|
||||
RETURN VALUE
|
||||
0 success
|
||||
@ -1292,10 +1315,11 @@ static int mysql_test_create_table(Prepared_statement *stmt)
|
||||
-1 error, not sent to client
|
||||
*/
|
||||
static int mysql_test_multiupdate(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables)
|
||||
TABLE_LIST *tables,
|
||||
bool converted)
|
||||
{
|
||||
int res;
|
||||
if ((res= multi_update_precheck(stmt->thd, tables)))
|
||||
if (!converted && (res= multi_update_precheck(stmt->thd, tables)))
|
||||
return res;
|
||||
return select_like_statement_test(stmt, tables, &mysql_multi_update_prepare);
|
||||
}
|
||||
@ -1325,7 +1349,19 @@ static int mysql_test_multidelete(Prepared_statement *stmt,
|
||||
uint fake_counter;
|
||||
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
|
||||
return res;
|
||||
return select_like_statement_test(stmt, tables, &mysql_multi_delete_prepare);
|
||||
if ((res= select_like_statement_test(stmt, tables,
|
||||
&mysql_multi_delete_prepare)))
|
||||
return res;
|
||||
if (!tables->table)
|
||||
{
|
||||
DBUG_ASSERT(tables->view &&
|
||||
tables->ancestor && tables->ancestor->next_local);
|
||||
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
|
||||
tables->view_db.str, tables->view_name.str);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1404,6 +1440,11 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
|
||||
|
||||
case SQLCOM_UPDATE:
|
||||
res= mysql_test_update(stmt, tables);
|
||||
if (res != 2)
|
||||
break;
|
||||
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
res= mysql_test_multiupdate(stmt, tables, res == 2);
|
||||
break;
|
||||
|
||||
case SQLCOM_DELETE:
|
||||
@ -1431,10 +1472,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
res= mysql_test_multidelete(stmt, tables);
|
||||
break;
|
||||
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
res= mysql_test_multiupdate(stmt, tables);
|
||||
break;
|
||||
|
||||
case SQLCOM_INSERT_SELECT:
|
||||
res= mysql_test_insert_select(stmt, tables);
|
||||
|
@ -87,6 +87,28 @@ static bool check_fields(THD *thd, List<Item> &items)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Process usual UPDATE
|
||||
|
||||
SYNOPSIS
|
||||
mysql_update()
|
||||
thd thread handler
|
||||
fields fields for update
|
||||
values values of fields for update
|
||||
conds WHERE clause expression
|
||||
order_num number of elemen in ORDER BY clause
|
||||
order ORDER BY clause list
|
||||
limit limit clause
|
||||
handle_duplicates how to handle duplicates
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
2 - privilege check and openning table passed, but we need to convert to
|
||||
multi-update because of view substitution
|
||||
1 - error and error sent to client
|
||||
-1 - error and error is not sent to client
|
||||
*/
|
||||
|
||||
int mysql_update(THD *thd,
|
||||
TABLE_LIST *table_list,
|
||||
List<Item> &fields,
|
||||
@ -96,7 +118,7 @@ int mysql_update(THD *thd,
|
||||
ha_rows limit,
|
||||
enum enum_duplicates handle_duplicates)
|
||||
{
|
||||
bool using_limit=limit != HA_POS_ERROR;
|
||||
bool using_limit=limit != HA_POS_ERROR;
|
||||
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
|
||||
bool used_key_is_modified, transactional_table, log_delayed;
|
||||
int error=0;
|
||||
@ -117,6 +139,15 @@ int mysql_update(THD *thd,
|
||||
|
||||
if ((error= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(error);
|
||||
|
||||
if (table_list->table == 0)
|
||||
{
|
||||
DBUG_ASSERT(table_list->view &&
|
||||
table_list->ancestor && table_list->ancestor->next_local);
|
||||
DBUG_PRINT("info", ("Switch to multi-update"));
|
||||
/* convert to multiupdate */
|
||||
return 2;
|
||||
}
|
||||
thd->proc_info="init";
|
||||
table= table_list->table;
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
@ -626,12 +657,30 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
if (tables_for_update & readonly_tables)
|
||||
{
|
||||
// find readonly table/view which cause error
|
||||
for (tl= leaves; tl; tl= tl->next_local)
|
||||
for (tl= leaves; tl; tl= tl->next_leaf)
|
||||
{
|
||||
if ((readonly_tables & tl->table->map) &&
|
||||
(tables_for_update & tl->table->map))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
|
||||
TABLE_LIST *table= tl->belong_to_view ? tl->belong_to_view : tl;
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table->alias, "UPDATE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check single table update for view compound from several tables */
|
||||
for (tl= table_list; tl; tl= tl->next_local)
|
||||
{
|
||||
if (tl->table == 0)
|
||||
{
|
||||
DBUG_ASSERT(tl->view &&
|
||||
tl->ancestor && tl->ancestor->next_local);
|
||||
TABLE_LIST *for_update= 0;
|
||||
if (tl->check_single_table(&for_update, tables_for_update))
|
||||
{
|
||||
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
|
||||
tl->view_db.str, tl->view_name.str);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
@ -647,19 +696,22 @@ int mysql_multi_update(THD *thd,
|
||||
COND *conds,
|
||||
ulong options,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
|
||||
bool converted)
|
||||
{
|
||||
int res;
|
||||
int res= 0;
|
||||
multi_update *result;
|
||||
DBUG_ENTER("mysql_multi_update");
|
||||
|
||||
if ((res= open_and_lock_tables(thd, table_list)))
|
||||
if (!converted && (res= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
if ((res= mysql_multi_update_prepare(thd)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
if (!(result= new multi_update(thd, table_list, fields, values,
|
||||
if (!(result= new multi_update(thd, table_list,
|
||||
thd->lex->select_lex.leaf_tables,
|
||||
fields, values,
|
||||
handle_duplicates)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
@ -677,12 +729,14 @@ int mysql_multi_update(THD *thd,
|
||||
|
||||
|
||||
multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
|
||||
TABLE_LIST *leaves_list,
|
||||
List<Item> *field_list, List<Item> *value_list,
|
||||
enum enum_duplicates handle_duplicates_arg)
|
||||
:all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0),
|
||||
updated(0), found(0), fields(field_list), values(value_list),
|
||||
table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg),
|
||||
do_update(1), trans_safe(0), transactional_tables(1)
|
||||
:all_tables(table_list), leaves(leaves_list), update_tables(0),
|
||||
thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list),
|
||||
values(value_list), table_count(0), copy_field(0),
|
||||
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
|
||||
transactional_tables(1)
|
||||
{}
|
||||
|
||||
|
||||
@ -730,7 +784,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
*/
|
||||
|
||||
update.empty();
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
|
||||
{
|
||||
/* TODO: add support of view of join support */
|
||||
TABLE *table=table_ref->table;
|
||||
@ -800,7 +854,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
which will cause an error when reading a row.
|
||||
(This issue is mostly relevent for MyISAM tables)
|
||||
*/
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
|
@ -465,23 +465,27 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
if ((view->updatable_view= (can_be_merged &&
|
||||
view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
|
||||
{
|
||||
if (thd->lex->select_lex.table_list.elements > 1)
|
||||
view->updatable_view= 0;
|
||||
else
|
||||
// TODO: change here when we will support UNIONs
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
// TODO: change here when we will support UNIONs
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)thd->lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
if (tbl->view && !tbl->updatable_view)
|
||||
{
|
||||
if (tbl->view && !tbl->updatable_view)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
}
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
}
|
||||
for (TABLE_LIST *up= tbl; up; up= up->embedding)
|
||||
{
|
||||
if (up->outer_join)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
goto loop_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
loop_out:
|
||||
if (sql_create_definition_file(&dir, &file, view_file_type,
|
||||
(gptr)view, view_parameters, 3))
|
||||
{
|
||||
@ -701,9 +705,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
old_lex->can_use_merged()) &&
|
||||
!old_lex->can_not_use_merged())
|
||||
{
|
||||
/*
|
||||
TODO: support multi tables substitutions
|
||||
*/
|
||||
/* lex should contain at least one table */
|
||||
DBUG_ASSERT(view_tables != 0);
|
||||
|
||||
@ -736,7 +737,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
/* multi table view */
|
||||
if (view_tables->next_local)
|
||||
{
|
||||
table->updatable= 0;
|
||||
/* make nested join structure for view tables */
|
||||
NESTED_JOIN *nested_join;
|
||||
if (!(nested_join= table->nested_join=
|
||||
@ -919,14 +919,16 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
uint i, elements_in_view;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
|
||||
if (!view->view)
|
||||
if (!view->view && !view->belong_to_view)
|
||||
DBUG_RETURN(FALSE); /* it is normal table */
|
||||
table= view->table;
|
||||
if (view->belong_to_view)
|
||||
view= view->belong_to_view;
|
||||
trans= view->field_translation;
|
||||
key_info_end= (key_info= table->key_info)+ table->keys;
|
||||
|
||||
elements_in_view= view->view->select_lex.item_list.elements;
|
||||
DBUG_ASSERT(view->table != 0 && view->field_translation != 0);
|
||||
DBUG_ASSERT(table != 0 && view->field_translation != 0);
|
||||
|
||||
/* Loop over all keys to see if a unique-not-null key is used */
|
||||
for (;key_info != key_info_end ; key_info++)
|
||||
@ -1002,21 +1004,30 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
insert_view_fields()
|
||||
list list for insertion
|
||||
view view for processing
|
||||
|
||||
RETURN
|
||||
0 - OK
|
||||
-1 - error (is not sent to cliet)
|
||||
*/
|
||||
|
||||
void insert_view_fields(List<Item> *list, TABLE_LIST *view)
|
||||
int insert_view_fields(List<Item> *list, TABLE_LIST *view)
|
||||
{
|
||||
uint elements_in_view= view->view->select_lex.item_list.elements;
|
||||
Field_translator *trans;
|
||||
DBUG_ENTER("insert_view_fields");
|
||||
|
||||
if (!(trans= view->field_translation))
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
for (uint i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
if (trans[i].item->type() == Item::FIELD_ITEM)
|
||||
list->push_back(trans[i].item);
|
||||
else
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ int mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
|
||||
|
||||
bool check_key_in_view(THD *thd, TABLE_LIST * view);
|
||||
|
||||
void insert_view_fields(List<Item> *list, TABLE_LIST *view);
|
||||
int insert_view_fields(List<Item> *list, TABLE_LIST *view);
|
||||
|
||||
frm_type_enum mysql_frm_type(char *path);
|
||||
|
||||
|
89
sql/table.cc
89
sql/table.cc
@ -1744,6 +1744,95 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find table in underlaying tables by mask and check that only this
|
||||
table sbelong to given mask
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::check_single_table()
|
||||
table reference on variable where to store found table
|
||||
(should be 0 on call, to find table, or point to table for
|
||||
unique test)
|
||||
map bit mask of tables
|
||||
|
||||
RETURN
|
||||
0 table not found or found only one
|
||||
1 found several tables
|
||||
*/
|
||||
|
||||
bool st_table_list::check_single_table(st_table_list **table, table_map map)
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
{
|
||||
if (tbl->table->map & map)
|
||||
{
|
||||
if (*table)
|
||||
return 1;
|
||||
else
|
||||
*table= tbl;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (tbl->check_single_table(table, map))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Set insert_values buffer
|
||||
|
||||
SYNOPSIS
|
||||
set_insert_values()
|
||||
mem_root memory pool for allocating
|
||||
|
||||
RETURN
|
||||
FALSE - OK
|
||||
TRUE - out of memory
|
||||
*/
|
||||
|
||||
bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
if (!table->insert_values &&
|
||||
!(table->insert_values= (byte *)alloc_root(mem_root,
|
||||
table->rec_buff_length)))
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(view && ancestor && ancestor->next_local);
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
if (tbl->set_insert_values(mem_root))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
clear insert_values reference
|
||||
|
||||
SYNOPSIS
|
||||
clear_insert_values()
|
||||
*/
|
||||
|
||||
void st_table_list::clear_insert_values()
|
||||
{
|
||||
if (table)
|
||||
table->insert_values= 0;
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(view && ancestor && ancestor->next_local);
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
tbl->clear_insert_values();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Field_iterator_view::set(TABLE_LIST *table)
|
||||
{
|
||||
ptr= table->field_translation;
|
||||
|
@ -277,6 +277,9 @@ typedef struct st_table_list
|
||||
void print(THD *thd, String *str);
|
||||
void save_and_clear_want_privilege();
|
||||
void restore_want_privilege();
|
||||
bool check_single_table(st_table_list **table, table_map map);
|
||||
bool set_insert_values(MEM_ROOT *mem_root);
|
||||
void clear_insert_values();
|
||||
inline st_table_list *next_independent()
|
||||
{
|
||||
if (view)
|
||||
|
Reference in New Issue
Block a user