summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2004-11-21 20:08:12 +0200
committerunknown <bell@sanja.is.com.ua>2004-11-21 20:08:12 +0200
commit5a00a868b74ffb6b220eb72c87ec38696ce9406c (patch)
tree76a673d7a9b20f184988993cc14ce455b1d73f70 /sql/sql_update.cc
parent436c7714dd6df991f2e968b313906d4b1e70db97 (diff)
parentc9497e2365461fb2547a8cfceb33b68a99d7fe0b (diff)
downloadmariadb-git-5a00a868b74ffb6b220eb72c87ec38696ce9406c.tar.gz
merge
sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_sum.cc: Auto merged sql/sp.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_view.h: Auto merged sql/sql_yacc.yy: Auto merged
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc171
1 files changed, 123 insertions, 48 deletions
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index c5167018701..0927fcfd9bc 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -86,25 +86,47 @@ static bool check_fields(THD *thd, List<Item> &items)
}
-bool mysql_update(THD *thd,
- TABLE_LIST *table_list,
- List<Item> &fields,
- List<Item> &values,
- COND *conds,
- uint order_num, ORDER *order,
- ha_rows limit,
- enum enum_duplicates handle_duplicates)
+/*
+ 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
+*/
+
+int mysql_update(THD *thd,
+ TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<Item> &values,
+ COND *conds,
+ uint order_num, ORDER *order,
+ ha_rows limit,
+ enum enum_duplicates handle_duplicates)
{
bool using_limit= limit != HA_POS_ERROR;
bool safe_update= thd->options & OPTION_SAFE_UPDATES;
bool used_key_is_modified, transactional_table, log_delayed;
bool ignore_err= (thd->lex->duplicates == DUP_IGNORE);
- bool res;
+ int res;
int error=0;
uint used_index;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
+ uint table_count= 0;
ulong query_id=thd->query_id, timestamp_query_id;
ha_rows updated, found;
key_map old_used_keys;
@@ -117,8 +139,26 @@ bool mysql_update(THD *thd,
LINT_INIT(used_index);
LINT_INIT(timestamp_query_id);
- if (open_and_lock_tables(thd, table_list))
- DBUG_RETURN(TRUE);
+ if (open_tables(thd, table_list, &table_count))
+ DBUG_RETURN(1);
+
+ 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"));
+ /* pass counter value */
+ thd->lex->table_count= table_count;
+ /* convert to multiupdate */
+ return 2;
+ }
+
+ if (lock_tables(thd, table_list, table_count) ||
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(thd->lex, &mysql_derived_filling)))
+ DBUG_RETURN(1);
+
thd->proc_info="init";
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -134,7 +174,7 @@ bool mysql_update(THD *thd,
table->grant.want_privilege);
#endif
if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE
/*
@@ -156,16 +196,16 @@ bool mysql_update(THD *thd,
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
select_lex->no_wrap_view_item= 0;
if (res)
- DBUG_RETURN(TRUE); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
if (table_list->view && check_fields(thd, fields))
{
- DBUG_RETURN(TRUE);
+ 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(TRUE);
+ DBUG_RETURN(1);
}
if (table->timestamp_field)
{
@@ -184,7 +224,7 @@ bool mysql_update(THD *thd,
if (setup_fields(thd, 0, table_list, values, 0, 0, 0))
{
free_underlaid_joins(thd, select_lex);
- DBUG_RETURN(TRUE); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
// Don't count on usage of 'only index' when calculating which key to use
@@ -197,10 +237,10 @@ bool mysql_update(THD *thd,
free_underlaid_joins(thd, select_lex);
if (error)
{
- DBUG_RETURN(TRUE); // Error in where
+ DBUG_RETURN(1); // Error in where
}
send_ok(thd); // No matching records
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
if (table->quick_keys.is_clear_all())
@@ -472,7 +512,7 @@ bool mysql_update(THD *thd,
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
thd->abort_on_warning= 0;
free_io_cache(table);
- DBUG_RETURN(error >= 0 || thd->net.report_error);
+ DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
err:
delete select;
@@ -483,7 +523,7 @@ err:
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
thd->abort_on_warning= 0;
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(1);
}
/*
@@ -519,8 +559,8 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
tables.table= table;
tables.alias= table_list->alias;
- if (setup_tables(thd, table_list, conds) ||
- setup_conds(thd, table_list, conds) ||
+ if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
+ setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
select_lex->setup_ref_array(thd, order_num) ||
setup_order(thd, select_lex->ref_pointer_array,
table_list, all_fields, all_fields, order) ||
@@ -578,42 +618,53 @@ bool mysql_multi_update_prepare(THD *thd)
TABLE_LIST *table_list= lex->query_tables;
List<Item> *fields= &lex->select_lex.item_list;
TABLE_LIST *tl;
+ TABLE_LIST *leaves;
table_map tables_for_update;
int res;
bool update_view= 0;
- uint table_count;
+ /*
+ if this multi-update was converted from usual update, here is table
+ counter else junk will be assigned here, but then replaced with real
+ count in open_tables()
+ */
+ uint table_count= lex->table_count;
const bool using_lock_tables= thd->locked_tables != 0;
+ bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
DBUG_ENTER("mysql_multi_update_prepare");
/* open tables and create derived ones, but do not lock and fill them */
- if (open_tables(thd, table_list, & table_count) ||
+ if ((original_multiupdate && open_tables(thd, table_list, & table_count)) ||
mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE);
/*
+ setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
+ second time, but this call will do nothing (there are check for second
+ call in setup_tables()).
+ */
+
+ if (setup_tables(thd, table_list, &lex->select_lex.where,
+ &lex->select_lex.leaf_tables, 0))
+ DBUG_RETURN(TRUE);
+ /*
Ensure that we have update privilege for all tables and columns in the
SET part
*/
- for (tl= table_list; tl; tl= tl->next_local)
+ for (tl= (leaves= lex->select_lex.leaf_tables); tl; tl= tl->next_leaf)
{
- 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=
+ TABLE *table= tl->table;
+ TABLE_LIST *tlist;
+ if (!(tlist= tl->belong_to_view?tl->belong_to_view:tl)->derived)
+ tlist->grant.want_privilege= table->grant.want_privilege=
(UPDATE_ACL & ~table->grant.privilege);
}
- /*
- setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
- second time, but this call will do nothing (there are check for second
- call in setup_tables()).
- */
- if (setup_tables(thd, table_list, &lex->select_lex.where) ||
- (lex->select_lex.no_wrap_view_item= 1,
+ if ((lex->select_lex.no_wrap_view_item= 1,
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
lex->select_lex.no_wrap_view_item= 0,
res))
@@ -638,14 +689,15 @@ bool mysql_multi_update_prepare(THD *thd)
/*
Setup timestamp handling and locking mode
*/
- for (tl= table_list; tl ; tl= tl->next_local)
+ for (tl= leaves; tl; tl= tl->next_leaf)
{
TABLE *table= tl->table;
+ TABLE_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl;
/* We only need SELECT privilege for columns in the values list */
- tl->grant.want_privilege= table->grant.want_privilege=
+ tlist->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege);
- // Only set timestamp column if this is not modified
+ /* Only set timestamp column if this is not modified */
if (table->timestamp_field &&
table->timestamp_field->query_id == thd->query_id)
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@@ -683,6 +735,23 @@ bool mysql_multi_update_prepare(THD *thd)
tl->table->reginfo.lock_type= tl->lock_type;
}
+ /* 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);
+ }
+ }
+ }
+
opened_tables= thd->status_var.opened_tables;
/* now lock and fill tables */
if (lock_tables(thd, table_list, table_count))
@@ -712,7 +781,8 @@ bool mysql_multi_update_prepare(THD *thd)
/* undone setup_tables() */
table_list->setup_is_done= 0;
- if (setup_tables(thd, table_list, &lex->select_lex.where) ||
+ if (setup_tables(thd, table_list, &lex->select_lex.where,
+ &lex->select_lex.leaf_tables, 0) ||
(lex->select_lex.no_wrap_view_item= 1,
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
lex->select_lex.no_wrap_view_item= 0,
@@ -739,14 +809,16 @@ bool mysql_multi_update(THD *thd,
enum enum_duplicates handle_duplicates,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
- bool res;
+ bool res= FALSE;
multi_update *result;
DBUG_ENTER("mysql_multi_update");
if (mysql_multi_update_prepare(thd))
DBUG_RETURN(TRUE);
- 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(TRUE);
@@ -770,12 +842,14 @@ bool 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)
{}
@@ -822,8 +896,9 @@ int multi_update::prepare(List<Item> &not_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;
if (tables_to_update & table->map)
{
@@ -890,10 +965,10 @@ int multi_update::prepare(List<Item> &not_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) &&
+ if (!(tables_to_update & table->map) &&
find_table_in_local_list(update_tables, table_ref->db,
table_ref->real_name))
table->no_cache= 1; // Disable row cache