mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
VIEW
two TABLE_LIST copy eliminated include/mysqld_error.h: errors of view libmysqld/Makefile.am: new view file mysql-test/r/connect.result: SHOW TABLE show type of table mysql-test/r/ctype_recoding.result: SHOW TABLE show type of table mysql-test/r/drop.result: SHOW TABLE show type of table mysql-test/r/grant.result: new two privileges (CRETEA|SHOW VIEW) mysql-test/r/lowercase_table.result: SHOW TABLE show type of table mysql-test/r/ps_1general.result: SHOW TABLE show type of table mysql-test/r/rename.result: SHOW TABLE show type of table mysql-test/r/rpl000009.result: SHOW TABLE show type of table mysql-test/r/rpl_error_ignored_table.result: SHOW TABLE show type of table mysql-test/r/select.result: SHOW TABLE show type of table mysql-test/r/system_mysql_db.result: SHOW TABLE show type of table new two privileges (CRETEA|SHOW VIEW) mysql-test/t/system_mysql_db_fix.test: removing all system tables scripts/mysql_fix_privilege_tables.sql: new two privileges (CRETEA|SHOW VIEW) sql/Makefile.am: new VIEW related file sql/ha_myisammrg.cc: two TABLE_LIST copy eliminated sql/item.cc: VIEW sql/item.h: VIEW sql/item_subselect.cc: VIEW sql/item_subselect.h: VIEW sql/lex.h: VIEW sql/lock.cc: VIEW sql/mysql_priv.h: VIEW sql/mysqld.cc: VIEW new parameter - sql_updatable_view_key sql/opt_sum.cc: two TABLE_LIST copy eliminated sql/set_var.cc: new parameter - sql_updatable_view_key sql/share/czech/errmsg.txt: errors messages of views sql/share/danish/errmsg.txt: errors messages of views sql/share/dutch/errmsg.txt: errors messages of views sql/share/english/errmsg.txt: errors messages of views sql/share/estonian/errmsg.txt: errors messages of views sql/share/french/errmsg.txt: errors messages of views sql/share/german/errmsg.txt: errors messages of views sql/share/greek/errmsg.txt: errors messages of views sql/share/hungarian/errmsg.txt: errors messages of views sql/share/italian/errmsg.txt: errors messages of views sql/share/japanese/errmsg.txt: errors messages of views sql/share/korean/errmsg.txt: errors messages of views sql/share/norwegian-ny/errmsg.txt: errors messages of views sql/share/norwegian/errmsg.txt: errors messages of views sql/share/polish/errmsg.txt: errors messages of views sql/share/portuguese/errmsg.txt: errors messages of views sql/share/romanian/errmsg.txt: errors messages of views sql/share/russian/errmsg.txt: errors messages of views sql/share/serbian/errmsg.txt: errors messages of views sql/share/slovak/errmsg.txt: errors messages of views sql/share/spanish/errmsg.txt: errors messages of views sql/share/swedish/errmsg.txt: errors messages of views sql/share/ukrainian/errmsg.txt: errors messages of views sql/slave.cc: two TABLE_LIST copy eliminated sql/sp.cc: VIEW sql/sql_acl.cc: VIEW sql/sql_acl.h: VIEW sql/sql_base.cc: VIEW sql/sql_cache.cc: two TABLE_LIST copy eliminated sql/sql_class.h: VIEW sql/sql_db.cc: two TABLE_LIST copy eliminated sql/sql_delete.cc: VIEW sql/sql_derived.cc: VIEW sql/sql_handler.cc: two TABLE_LIST copy eliminated sql/sql_help.cc: two TABLE_LIST copy eliminated sql/sql_insert.cc: VIEW sql/sql_lex.cc: VIEW sql/sql_lex.h: VIEW sql/sql_load.cc: VIEW sql/sql_olap.cc: VIEW sql/sql_parse.cc: two TABLE_LIST copy eliminated VIEW sql/sql_prepare.cc: VIEW sql/sql_rename.cc: two TABLE_LIST copy eliminated sql/sql_select.cc: VIEW sql/sql_show.cc: VIEW sql/sql_table.cc: VIEW sql/sql_union.cc: VIEW sql/sql_update.cc: VIEW sql/sql_yacc.yy: VIEW sql/table.cc: VIEW sql/table.h: VIEW sql/tztime.cc: two TABLE_LIST copy eliminated sql/unireg.h: VIEW tests/client_test.c: VIEW
This commit is contained in:
@ -48,6 +48,35 @@ static bool compare_record(TABLE *table, ulong query_id)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
check that all fields are real fields
|
||||
|
||||
SYNOPSIS
|
||||
check_fields()
|
||||
items Items for check
|
||||
|
||||
RETURN
|
||||
TRUE Items can't be used in UPDATE
|
||||
FALSE Items are OK
|
||||
*/
|
||||
|
||||
static bool check_fields(List<Item> &items)
|
||||
{
|
||||
List_iterator_fast<Item> it(items);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
if (item->type() != Item::FIELD_ITEM)
|
||||
{
|
||||
/* as far as item comes from VIEW select list it has name */
|
||||
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int mysql_update(THD *thd,
|
||||
TABLE_LIST *table_list,
|
||||
List<Item> &fields,
|
||||
@ -71,8 +100,6 @@ int mysql_update(THD *thd,
|
||||
TABLE *table;
|
||||
SQL_SELECT *select;
|
||||
READ_RECORD info;
|
||||
TABLE_LIST *update_table_list= ((TABLE_LIST*)
|
||||
thd->lex->select_lex.table_list.first);
|
||||
DBUG_ENTER("mysql_update");
|
||||
|
||||
LINT_INIT(used_index);
|
||||
@ -89,10 +116,12 @@ int mysql_update(THD *thd,
|
||||
table->quick_keys.clear_all();
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
want_privilege= table->grant.want_privilege;
|
||||
/* In case of view TABLE_LIST contain right privilages request */
|
||||
want_privilege= (table_list->view ?
|
||||
table_list->grant.want_privilege :
|
||||
table->grant.want_privilege);
|
||||
#endif
|
||||
if ((error= mysql_prepare_update(thd, table_list, update_table_list,
|
||||
&conds, order_num, order)))
|
||||
if ((error= mysql_prepare_update(thd, table_list, &conds, order_num, order)))
|
||||
DBUG_RETURN(error);
|
||||
|
||||
old_used_keys= table->used_keys; // Keys used in WHERE
|
||||
@ -108,10 +137,19 @@ int mysql_update(THD *thd,
|
||||
|
||||
/* Check the fields we are going to modify */
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.want_privilege=want_privilege;
|
||||
table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
|
||||
#endif
|
||||
if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
|
||||
if (setup_fields(thd, 0, table_list, fields, 1, 0, 0))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
if (check_fields(fields))
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (!table_list->updatable || check_key_in_view(thd, table_list))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (table->timestamp_field)
|
||||
{
|
||||
// Don't set timestamp column if this is modified
|
||||
@ -123,9 +161,10 @@ int mysql_update(THD *thd,
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/* Check values */
|
||||
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
|
||||
table_list->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
#endif
|
||||
if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
|
||||
if (setup_fields(thd, 0, table_list, values, 0, 0, 0))
|
||||
{
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
@ -228,7 +267,7 @@ int mysql_update(THD *thd,
|
||||
if (select && select->quick && select->quick->reset())
|
||||
goto err;
|
||||
init_read_record(&info,thd,table,select,0,1);
|
||||
|
||||
|
||||
thd->proc_info="Searching rows for update";
|
||||
uint tmp_limit= limit;
|
||||
|
||||
@ -407,8 +446,7 @@ err:
|
||||
SYNOPSIS
|
||||
mysql_prepare_update()
|
||||
thd - thread handler
|
||||
table_list - global table list
|
||||
update_table_list - local table list of UPDATE SELECT_LEX
|
||||
table_list - global/local table list
|
||||
conds - conditions
|
||||
order_num - number of ORDER BY list entries
|
||||
order - ORDER BY clause list
|
||||
@ -419,7 +457,6 @@ err:
|
||||
-1 - error (message is not sent to user)
|
||||
*/
|
||||
int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
TABLE_LIST *update_table_list,
|
||||
Item **conds, uint order_num, ORDER *order)
|
||||
{
|
||||
TABLE *table= table_list->table;
|
||||
@ -429,34 +466,30 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
DBUG_ENTER("mysql_prepare_update");
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
|
||||
table_list->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
#endif
|
||||
|
||||
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
|
||||
tables.table= table;
|
||||
tables.alias= table_list->alias;
|
||||
|
||||
if (setup_tables(update_table_list) ||
|
||||
setup_conds(thd, update_table_list, conds) ||
|
||||
if (setup_tables(thd, table_list, conds) ||
|
||||
setup_conds(thd, table_list, conds) ||
|
||||
select_lex->setup_ref_array(thd, order_num) ||
|
||||
setup_order(thd, select_lex->ref_pointer_array,
|
||||
update_table_list, all_fields, all_fields, order) ||
|
||||
table_list, all_fields, all_fields, order) ||
|
||||
setup_ftfuncs(select_lex))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
/* Check that we are not using table that we are updating in a sub select */
|
||||
if (find_real_table_in_list(table_list->next,
|
||||
if (find_real_table_in_list(table_list->next_global,
|
||||
table_list->db, table_list->real_name))
|
||||
{
|
||||
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (thd->current_arena && select_lex->first_execution)
|
||||
{
|
||||
select_lex->prep_where= select_lex->where;
|
||||
select_lex->first_execution= 0;
|
||||
}
|
||||
|
||||
select_lex->fix_prepare_information(thd, conds);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -469,6 +502,101 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
|
||||
Setup multi-update handling and call SELECT to do the join
|
||||
*/
|
||||
|
||||
/*
|
||||
make update specific preparation and checks after opening tables
|
||||
|
||||
SYNOPSIS
|
||||
mysql_multi_update_prepare()
|
||||
thd thread handler
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
-1 Error
|
||||
*/
|
||||
|
||||
int mysql_multi_update_prepare(THD *thd)
|
||||
{
|
||||
LEX *lex= thd->lex;
|
||||
TABLE_LIST *table_list= lex->query_tables;
|
||||
List<Item> *fields= &lex->select_lex.item_list;
|
||||
TABLE_LIST *tl;
|
||||
table_map tables_for_update= 0, readonly_tables= 0;
|
||||
DBUG_ENTER("mysql_multi_update_prepare");
|
||||
/*
|
||||
Ensure that we have update privilege for all tables and columns in the
|
||||
SET part
|
||||
*/
|
||||
for (tl= table_list; tl; tl= tl->next_local)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
/*
|
||||
Update of derived tables is checked later
|
||||
We don't check privileges here, becasue then we would get error
|
||||
"UPDATE command denided .. for column N" instead of
|
||||
"Target table ... is not updatable"
|
||||
*/
|
||||
if (!tl->derived)
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
(UPDATE_ACL & ~table->grant.privilege);
|
||||
}
|
||||
|
||||
/*
|
||||
setup_tables() need for VIEWs. JOIN::prepare() will not do it second
|
||||
time.
|
||||
*/
|
||||
if (setup_tables(thd, table_list, &lex->select_lex.where) ||
|
||||
setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
|
||||
DBUG_RETURN(-1);
|
||||
if (check_fields(*fields))
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
{
|
||||
// Find tables used in items
|
||||
List_iterator_fast<Item> it(*fields);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
tables_for_update|= item->used_tables();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Count tables and setup timestamp handling
|
||||
*/
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
|
||||
/* We only need SELECT privilege for columns in the values list */
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
// Only set timestamp column if this is not modified
|
||||
if (table->timestamp_field &&
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
table->timestamp_on_update_now= 0;
|
||||
|
||||
if (!tl->updatable || check_key_in_view(thd, tl))
|
||||
readonly_tables|= table->map;
|
||||
}
|
||||
if (tables_for_update & readonly_tables)
|
||||
{
|
||||
// find readonly table/view which cause error
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
{
|
||||
if ((readonly_tables & tl->table->map) &&
|
||||
(tables_for_update & tl->table->map))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
DBUG_RETURN (0);
|
||||
}
|
||||
|
||||
|
||||
int mysql_multi_update(THD *thd,
|
||||
TABLE_LIST *table_list,
|
||||
List<Item> *fields,
|
||||
@ -480,95 +608,21 @@ int mysql_multi_update(THD *thd,
|
||||
{
|
||||
int res;
|
||||
multi_update *result;
|
||||
TABLE_LIST *tl;
|
||||
TABLE_LIST *update_list= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
|
||||
table_map item_tables= 0, derived_tables= 0;
|
||||
DBUG_ENTER("mysql_multi_update");
|
||||
|
||||
if ((res=open_and_lock_tables(thd,table_list)))
|
||||
if ((res= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
select_lex->select_limit= HA_POS_ERROR;
|
||||
if ((res= mysql_multi_update_prepare(thd)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
/*
|
||||
Ensure that we have update privilege for all tables and columns in the
|
||||
SET part
|
||||
*/
|
||||
for (tl= update_list; tl; tl= tl->next)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
/*
|
||||
Update of derived tables is checked later
|
||||
We don't check privileges here, becasue then we would get error
|
||||
"UPDATE command denided .. for column N" instead of
|
||||
"Target table ... is not updatable"
|
||||
*/
|
||||
if (!tl->derived)
|
||||
table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege);
|
||||
}
|
||||
|
||||
if (thd->lex->derived_tables)
|
||||
{
|
||||
// Assign table map values to check updatability of derived tables
|
||||
uint tablenr=0;
|
||||
for (TABLE_LIST *table_list= update_list;
|
||||
table_list;
|
||||
table_list= table_list->next, tablenr++)
|
||||
{
|
||||
table_list->table->map= (table_map) 1 << tablenr;
|
||||
}
|
||||
}
|
||||
if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
|
||||
DBUG_RETURN(-1);
|
||||
if (thd->lex->derived_tables)
|
||||
{
|
||||
// Find tables used in items
|
||||
List_iterator_fast<Item> it(*fields);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
item_tables|= item->used_tables();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Count tables and setup timestamp handling
|
||||
*/
|
||||
for (tl= update_list; tl; tl= tl->next)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
|
||||
/* We only need SELECT privilege for columns in the values list */
|
||||
table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege);
|
||||
// Only set timestamp column if this is not modified
|
||||
if (table->timestamp_field &&
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
table->timestamp_on_update_now= 0;
|
||||
|
||||
if (tl->derived)
|
||||
derived_tables|= table->map;
|
||||
}
|
||||
if (thd->lex->derived_tables && (item_tables & derived_tables))
|
||||
{
|
||||
// find derived table which cause error
|
||||
for (tl= update_list; tl; tl= tl->next)
|
||||
{
|
||||
if (tl->derived && (item_tables & tl->table->map))
|
||||
{
|
||||
my_printf_error(ER_NON_UPDATABLE_TABLE, ER(ER_NON_UPDATABLE_TABLE),
|
||||
MYF(0), tl->alias, "UPDATE");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(result=new multi_update(thd, update_list, fields, values,
|
||||
handle_duplicates)))
|
||||
if (!(result= new multi_update(thd, table_list, fields, values,
|
||||
handle_duplicates)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
List<Item> total_list;
|
||||
res= mysql_select(thd, &select_lex->ref_pointer_array,
|
||||
select_lex->get_table_list(), select_lex->with_wild,
|
||||
table_list, select_lex->with_wild,
|
||||
total_list,
|
||||
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
|
||||
(ORDER *)NULL,
|
||||
@ -633,7 +687,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
*/
|
||||
|
||||
update.empty();
|
||||
for (table_ref= all_tables; table_ref; table_ref=table_ref->next)
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (tables_to_update & table->map)
|
||||
@ -642,7 +696,7 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
sizeof(*tl));
|
||||
if (!tl)
|
||||
DBUG_RETURN(1);
|
||||
update.link_in_list((byte*) tl, (byte**) &tl->next);
|
||||
update.link_in_list((byte*) tl, (byte**) &tl->next_local);
|
||||
tl->shared= table_count++;
|
||||
table->no_keyread=1;
|
||||
table->used_keys.clear_all();
|
||||
@ -702,7 +756,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)
|
||||
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
@ -737,7 +791,7 @@ multi_update::initialize_tables(JOIN *join)
|
||||
table_to_update= 0;
|
||||
|
||||
/* Create a temporary table for keys to all tables, except main table */
|
||||
for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
|
||||
for (table_ref= update_tables; table_ref; table_ref= table_ref->next_local)
|
||||
{
|
||||
TABLE *table=table_ref->table;
|
||||
uint cnt= table_ref->shared;
|
||||
@ -849,7 +903,7 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
|
||||
multi_update::~multi_update()
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
for (table= update_tables ; table; table= table->next)
|
||||
for (table= update_tables ; table; table= table->next_local)
|
||||
table->table->no_keyread= table->table->no_cache= 0;
|
||||
|
||||
if (tmp_tables)
|
||||
@ -876,7 +930,7 @@ bool multi_update::send_data(List<Item> ¬_used_values)
|
||||
TABLE_LIST *cur_table;
|
||||
DBUG_ENTER("multi_update::send_data");
|
||||
|
||||
for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
|
||||
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
|
||||
{
|
||||
TABLE *table= cur_table->table;
|
||||
/*
|
||||
@ -990,7 +1044,7 @@ int multi_update::do_updates(bool from_send_error)
|
||||
do_update= 0; // Don't retry this function
|
||||
if (!found)
|
||||
DBUG_RETURN(0);
|
||||
for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
|
||||
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local)
|
||||
{
|
||||
byte *ref_pos;
|
||||
|
||||
|
Reference in New Issue
Block a user