Commit 694c7334 authored by unknown's avatar unknown

merged


sql/mysql_priv.h:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
parents 47af809c 0029b4e7
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B));
INSERT t1 VALUES (1,2,10), (3,4,20);
INSERT t1 VALUES (5,6,30) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
a b c
1 2 10
3 4 20
5 6 30
INSERT t1 VALUES (5,7,40) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
a b c
1 2 10
3 4 20
5 6 130
INSERT t1 VALUES (8,4,50) ON DUPLICATE KEY UPDATE SET c=c+1000;
SELECT * FROM t1;
a b c
1 2 10
3 4 1020
5 6 130
INSERT t1 VALUES (1,4,60) ON DUPLICATE KEY UPDATE SET c=c+10000;
SELECT * FROM t1;
a b c
1 2 10010
3 4 1020
5 6 130
INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE SET c=c+100000, b=4;
Duplicate entry '4' for key 2
SELECT * FROM t1;
a b c
1 2 10010
3 4 1020
5 6 130
TRUNCATE TABLE t1;
INSERT t1 VALUES (1,2,10), (3,4,20);
INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
a b c
1 2 10
3 4 120
5 6 30
8 9 60
DROP TABLE t1;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B));
INSERT t1 VALUES (1,2,10), (3,4,20);
INSERT t1 VALUES (5,6,30) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
INSERT t1 VALUES (5,7,40) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
INSERT t1 VALUES (8,4,50) ON DUPLICATE KEY UPDATE SET c=c+1000;
SELECT * FROM t1;
INSERT t1 VALUES (1,4,60) ON DUPLICATE KEY UPDATE SET c=c+10000;
SELECT * FROM t1;
-- error 1062
INSERT t1 VALUES (1,9,70) ON DUPLICATE KEY UPDATE SET c=c+100000, b=4;
SELECT * FROM t1;
TRUNCATE TABLE t1;
INSERT t1 VALUES (1,2,10), (3,4,20);
INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE SET c=c+100;
SELECT * FROM t1;
DROP TABLE t1;
...@@ -444,7 +444,8 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, ...@@ -444,7 +444,8 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
ORDER *order, ha_rows limit, ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates); enum enum_duplicates handle_duplicates);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, enum_duplicates flag); List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag);
void kill_delayed_threads(void); void kill_delayed_threads(void);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order, int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
ha_rows rows, ulong options); ha_rows rows, ulong options);
......
...@@ -29,7 +29,7 @@ class Slave_log_event; ...@@ -29,7 +29,7 @@ class Slave_log_event;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE }; enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE, DUP_UPDATE };
enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN }; enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL }; DELAY_KEY_WRITE_ALL };
...@@ -188,6 +188,9 @@ typedef struct st_copy_info { ...@@ -188,6 +188,9 @@ typedef struct st_copy_info {
ha_rows error_count; ha_rows error_count;
enum enum_duplicates handle_duplicates; enum enum_duplicates handle_duplicates;
int escape_char, last_errno; int escape_char, last_errno;
/* for INSERT ... UPDATE */
List<Item> *update_fields;
List<Item> *update_values;
} COPY_INFO; } COPY_INFO;
......
...@@ -97,8 +97,12 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, ...@@ -97,8 +97,12 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
} }
int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, int mysql_insert(THD *thd,TABLE_LIST *table_list,
List<List_item> &values_list,enum_duplicates duplic) List<Item> &fields,
List<List_item> &values_list,
List<Item> &update_fields,
List<Item> &update_values,
enum_duplicates duplic)
{ {
int error; int error;
bool log_on= ((thd->options & OPTION_UPDATE_LOG) || bool log_on= ((thd->options & OPTION_UPDATE_LOG) ||
...@@ -126,7 +130,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -126,7 +130,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if ((lock_type == TL_WRITE_DELAYED && if ((lock_type == TL_WRITE_DELAYED &&
((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) || ((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
thd->slave_thread)) || thd->slave_thread)) ||
(lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE)) (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
(duplic == DUP_UPDATE))
lock_type=TL_WRITE; lock_type=TL_WRITE;
table_list->lock_type= lock_type; table_list->lock_type= lock_type;
...@@ -166,7 +171,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -166,7 +171,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
values= its++; values= its++;
if (check_insert_fields(thd,table,fields,*values,1) || if (check_insert_fields(thd,table,fields,*values,1) ||
setup_tables(insert_table_list) || setup_tables(insert_table_list) ||
setup_fields(thd, insert_table_list, *values, 0, 0, 0)) setup_fields(thd, insert_table_list, *values, 0, 0, 0) ||
(duplic == DUP_UPDATE &&
(setup_fields(thd, insert_table_list, update_fields, 0, 0, 0) ||
setup_fields(thd, insert_table_list, update_values, 0, 0, 0))))
{ {
table->time_stamp= save_time_stamp; table->time_stamp= save_time_stamp;
goto abort; goto abort;
...@@ -203,6 +211,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -203,6 +211,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
info.records=info.deleted=info.copied=0; info.records=info.deleted=info.copied=0;
info.handle_duplicates=duplic; info.handle_duplicates=duplic;
info.update_fields=&update_fields;
info.update_values=&update_values;
// Don't count warnings for simple inserts // Don't count warnings for simple inserts
if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS)) if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS))
thd->count_cuted_fields = 1; thd->count_cuted_fields = 1;
...@@ -212,7 +222,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -212,7 +222,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
error=0; error=0;
id=0; id=0;
thd->proc_info="update"; thd->proc_info="update";
if (duplic == DUP_IGNORE || duplic == DUP_REPLACE) if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if ((bulk_insert= (values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT && if ((bulk_insert= (values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT &&
lock_type != TL_WRITE_DELAYED && lock_type != TL_WRITE_DELAYED &&
...@@ -358,7 +368,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, ...@@ -358,7 +368,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
table->next_number_field=0; table->next_number_field=0;
thd->count_cuted_fields=0; thd->count_cuted_fields=0;
thd->next_insert_id=0; // Reset this if wrongly used thd->next_insert_id=0; // Reset this if wrongly used
if (duplic == DUP_IGNORE || duplic == DUP_REPLACE) if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (error) if (error)
goto abort; goto abort;
...@@ -410,7 +420,8 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -410,7 +420,8 @@ int write_record(TABLE *table,COPY_INFO *info)
char *key=0; char *key=0;
info->records++; info->records++;
if (info->handle_duplicates == DUP_REPLACE) if (info->handle_duplicates == DUP_REPLACE ||
info->handle_duplicates == DUP_UPDATE)
{ {
while ((error=table->file->write_row(table->record[0]))) while ((error=table->file->write_row(table->record[0])))
{ {
...@@ -427,7 +438,9 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -427,7 +438,9 @@ int write_record(TABLE *table,COPY_INFO *info)
was used. This ensures that we don't get a problem when the was used. This ensures that we don't get a problem when the
whole range of the key has been used. whole range of the key has been used.
*/ */
if (table->next_number_field && key_nr == table->next_number_index && if (info->handle_duplicates == DUP_REPLACE &&
table->next_number_field &&
key_nr == table->next_number_index &&
table->file->auto_increment_column_changed) table->file->auto_increment_column_changed)
goto err; goto err;
if (table->file->table_flags() & HA_DUPP_POS) if (table->file->table_flags() & HA_DUPP_POS)
...@@ -459,6 +472,22 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -459,6 +472,22 @@ int write_record(TABLE *table,COPY_INFO *info)
HA_READ_KEY_EXACT)))) HA_READ_KEY_EXACT))))
goto err; goto err;
} }
if (info->handle_duplicates == DUP_UPDATE)
{
/* we don't check for other UNIQUE keys - the first row
that matches, is updated. If update causes a conflict again,
an error is returned
*/
restore_record(table,1);
if (fill_record(*info->update_fields,*info->update_values))
goto err;
if ((error=table->file->update_row(table->record[1],table->record[0])))
goto err;
info->deleted++;
break;
}
else /* DUP_REPLACE */
{
if (last_uniq_key(table,key_nr)) if (last_uniq_key(table,key_nr))
{ {
if ((error=table->file->update_row(table->record[1],table->record[0]))) if ((error=table->file->update_row(table->record[1],table->record[0])))
...@@ -470,6 +499,7 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -470,6 +499,7 @@ int write_record(TABLE *table,COPY_INFO *info)
goto err; goto err;
info->deleted++; info->deleted++;
} }
}
info->copied++; info->copied++;
} }
else if ((error=table->file->write_row(table->record[0]))) else if ((error=table->file->write_row(table->record[0])))
......
...@@ -1972,14 +1972,21 @@ mysql_execute_command(THD *thd) ...@@ -1972,14 +1972,21 @@ mysql_execute_command(THD *thd)
case SQLCOM_REPLACE: case SQLCOM_REPLACE:
case SQLCOM_INSERT: case SQLCOM_INSERT:
{ {
my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
ulong privilege= (lex->duplicates == DUP_REPLACE ? ulong privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL); INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
if (check_access(thd,privilege,tables->db,&tables->grant.privilege)) if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */ goto error; /* purecov: inspected */
if (grant_option && check_grant(thd,privilege,tables)) if (grant_option && check_grant(thd,privilege,tables))
goto error; goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
res = mysql_insert(thd,tables,lex->field_list,lex->many_values, res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
lex->duplicates); select_lex->item_list, lex->value_list,
(update ? DUP_UPDATE : lex->duplicates));
if (thd->net.report_error) if (thd->net.report_error)
res= -1; res= -1;
break; break;
...@@ -2302,7 +2309,7 @@ mysql_execute_command(THD *thd) ...@@ -2302,7 +2309,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOAD: case SQLCOM_LOAD:
{ {
uint privilege= (lex->duplicates == DUP_REPLACE ? uint privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL); INSERT_ACL | DELETE_ACL : INSERT_ACL);
if (!lex->local_file) if (!lex->local_file)
{ {
......
...@@ -3053,7 +3053,7 @@ expr_or_default: ...@@ -3053,7 +3053,7 @@ expr_or_default:
opt_insert_update: opt_insert_update:
/* empty */ /* empty */
| ON DUPLICATE KEY_SYM UPDATE_SYM SET update_list | ON DUPLICATE
{ /* for simplisity, let's forget about { /* for simplisity, let's forget about
INSERT ... SELECT ... UPDATE INSERT ... SELECT ... UPDATE
for a moment */ for a moment */
...@@ -3063,6 +3063,7 @@ opt_insert_update: ...@@ -3063,6 +3063,7 @@ opt_insert_update:
YYABORT; YYABORT;
} }
} }
KEY_SYM UPDATE_SYM SET update_list
; ;
/* Update rows in a table */ /* Update rows in a table */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment