summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <acurtis@pcgem.rdg.cyberkinetica.com>2004-12-13 14:19:20 +0000
committerunknown <acurtis@pcgem.rdg.cyberkinetica.com>2004-12-13 14:19:20 +0000
commitc9a0e4ad5d59b37cdc3de4931b513f9af2e31541 (patch)
tree009488f20ad1f565e228f5198e19c2a77c593051 /sql
parentc04900bea926176133e22eb33cc4cc06742b413a (diff)
parent46364ddb1978802ad9bf5418738b03d0cfe8bd61 (diff)
downloadmariadb-git-c9a0e4ad5d59b37cdc3de4931b513f9af2e31541.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into pcgem.rdg.cyberkinetica.com:/usr/home/acurtis/work/wl2274.2
Diffstat (limited to 'sql')
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/sql_class.h10
-rw-r--r--sql/sql_insert.cc27
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc45
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_yacc.yy45
8 files changed, 64 insertions, 69 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 8350122c4e2..c90935f4cf9 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -362,7 +362,6 @@ bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
int multi_update_precheck(THD *thd, TABLE_LIST *tables);
int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
-int insert_select_precheck(THD *thd, TABLE_LIST *tables);
int update_precheck(THD *thd, TABLE_LIST *tables);
int delete_precheck(THD *thd, TABLE_LIST *tables);
int insert_precheck(THD *thd, TABLE_LIST *tables);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 419c087afbc..169835f3324 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1238,6 +1238,16 @@ class select_insert :public select_result_interceptor {
bzero((char*) &info,sizeof(info));
info.handle_duplicates=duplic;
}
+ select_insert(TABLE *table_par, List<Item> *fields_par,
+ List<Item> *update_fields, List<Item> *update_values,
+ enum_duplicates duplic)
+ :table(table_par), fields(fields_par), last_insert_id(0)
+ {
+ bzero((char*) &info,sizeof(info));
+ info.handle_duplicates=duplic;
+ info.update_fields= update_fields;
+ info.update_values= update_values;
+ }
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 768acb0cf9e..ce64890523a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -197,15 +197,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->used_tables=0;
values= its++;
- if (duplic == DUP_UPDATE && !table->insert_values)
- {
- /* 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)
- goto abort;
- }
-
if (mysql_prepare_insert(thd, table_list, insert_table_list, table,
fields, values, update_fields,
update_values, duplic))
@@ -448,14 +439,24 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
enum_duplicates duplic)
{
DBUG_ENTER("mysql_prepare_insert");
- if (check_insert_fields(thd, table, fields, *values, 1) ||
+ if (duplic == DUP_UPDATE && !table->insert_values)
+ {
+ /* 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)
+ DBUG_RETURN(-1);
+ }
+ if ((values && check_insert_fields(thd, table, fields, *values, 1)) ||
setup_tables(insert_table_list) ||
- setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
+ (values && setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) ||
(duplic == DUP_UPDATE &&
(setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0) ||
setup_fields(thd, 0, insert_table_list, update_values, 1, 0, 0))))
DBUG_RETURN(-1);
- if (find_real_table_in_list(table_list->next,
+ if ((thd->lex->sql_command==SQLCOM_INSERT ||
+ thd->lex->sql_command==SQLCOM_REPLACE) &&
+ find_real_table_in_list(table_list->next,
table_list->db, table_list->real_name))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
@@ -550,8 +551,10 @@ int write_record(TABLE *table,COPY_INFO *info)
that matches, is updated. If update causes a conflict again,
an error is returned
*/
+ DBUG_ASSERT(table->insert_values != NULL);
store_record(table,insert_values);
restore_record(table,record[1]);
+ DBUG_ASSERT(info->update_fields->elements==info->update_values->elements);
if (fill_record(*info->update_fields, *info->update_values, 0))
goto err;
if ((error=table->file->update_row(table->record[1],table->record[0])))
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 1d9afcc94a4..d2ac0df1472 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -123,6 +123,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
+ lex->update_list.empty();
lex->param_list.empty();
lex->unit.next= lex->unit.master=
lex->unit.link_next= lex->unit.return_to= 0;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b055a022eb4..8421be7e735 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -587,7 +587,7 @@ typedef struct st_lex
List<LEX_COLUMN> columns;
List<Key> key_list;
List<create_field> create_list;
- List<Item> *insert_list,field_list,value_list;
+ List<Item> *insert_list,field_list,value_list,update_list;
List<List_item> many_values;
List<set_var_base> var_list;
List<Item_param> param_list;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e73c3d95b42..8dc1339993e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2717,7 +2717,7 @@ unsent_create_error:
if ((res= insert_precheck(thd, tables)))
break;
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- select_lex->item_list, lex->value_list,
+ lex->update_list, lex->value_list,
lex->duplicates);
if (thd->net.report_error)
res= -1;
@@ -2727,7 +2727,7 @@ unsent_create_error:
case SQLCOM_INSERT_SELECT:
{
TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
- if ((res= insert_select_precheck(thd, tables)))
+ if ((res= insert_precheck(thd, tables)))
break;
/* Fix lock for first table */
@@ -2749,11 +2749,16 @@ unsent_create_error:
select_lex->options |= OPTION_BUFFER_RESULT;
}
-
if (!(res= open_and_lock_tables(thd, tables)) &&
+ !(res= mysql_prepare_insert(thd, tables, first_local_table,
+ tables->table, lex->field_list, 0,
+ lex->update_list, lex->value_list,
+ lex->duplicates)) &&
(result= new select_insert(tables->table, &lex->field_list,
+ &lex->update_list, &lex->value_list,
lex->duplicates)))
{
+ TABLE *table= tables->table;
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first= (byte*) first_local_table->next;
/*
@@ -2766,6 +2771,7 @@ unsent_create_error:
lex->select_lex.table_list.first= (byte*) first_local_table;
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
+ table->insert_values= 0;
if (thd->net.report_error)
res= -1;
}
@@ -5305,33 +5311,6 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
/*
- INSERT ... SELECT query pre-check
-
- SYNOPSIS
- insert_delete_precheck()
- thd Thread handler
- tables Global table list
-
- RETURN VALUE
- 0 OK
- 1 Error (message is sent to user)
- -1 Error (message is not sent to user)
-*/
-
-int insert_select_precheck(THD *thd, TABLE_LIST *tables)
-{
- DBUG_ENTER("insert_select_precheck");
- /*
- Check that we have modify privileges for the first table and
- select privileges for the rest
- */
- ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
- DBUG_RETURN(check_one_table_access(thd, privilege, tables) ? 1 : 0);
-}
-
-
-/*
simple UPDATE query pre-check
SYNOPSIS
@@ -5402,6 +5381,10 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
LEX *lex= thd->lex;
DBUG_ENTER("insert_precheck");
+ /*
+ Check that we have modify privileges for the first table and
+ select privileges for the rest
+ */
ulong privilege= INSERT_ACL |
(lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) |
(lex->duplicates == DUP_UPDATE ? UPDATE_ACL : 0);
@@ -5409,7 +5392,7 @@ int insert_precheck(THD *thd, TABLE_LIST *tables)
if (check_one_table_access(thd, privilege, tables))
DBUG_RETURN(1);
- if (lex->select_lex.item_list.elements != lex->value_list.elements)
+ if (lex->update_list.elements != lex->value_list.elements)
{
my_error(ER_WRONG_VALUE_COUNT, MYF(0));
DBUG_RETURN(-1);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index bcb9d18d827..f4a96d751cd 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1343,7 +1343,7 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
{
int res;
LEX *lex= stmt->lex;
- if ((res= insert_select_precheck(stmt->thd, tables)))
+ if ((res= insert_precheck(stmt->thd, tables)))
return res;
TABLE_LIST *first_local_table=
(TABLE_LIST *)lex->select_lex.table_list.first;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1b629e72ecc..a09694ee1e6 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4161,21 +4161,8 @@ expr_or_default:
opt_insert_update:
/* empty */
- | ON DUPLICATE_SYM
- {
- LEX *lex= Lex;
- /*
- For simplicity, let's forget about INSERT ... SELECT ... UPDATE
- for a moment.
- */
- if (lex->sql_command != SQLCOM_INSERT)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
- lex->duplicates= DUP_UPDATE;
- }
- KEY_SYM UPDATE_SYM update_list
+ | ON DUPLICATE_SYM { Lex->duplicates= DUP_UPDATE; }
+ KEY_SYM UPDATE_SYM insert_update_list
;
/* Update rows in a table */
@@ -4211,16 +4198,28 @@ update:
;
update_list:
- update_list ',' simple_ident equal expr_or_default
+ update_list ',' update_elem
+ | update_elem;
+
+update_elem:
+ simple_ident equal expr_or_default
{
- if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5))
+ if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
YYABORT;
- }
- | simple_ident equal expr_or_default
- {
- if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
- YYABORT;
- };
+ };
+
+insert_update_list:
+ insert_update_list ',' insert_update_elem
+ | insert_update_elem;
+
+insert_update_elem:
+ simple_ident equal expr_or_default
+ {
+ LEX *lex= Lex;
+ if (lex->update_list.push_back($1) ||
+ lex->value_list.push_back($3))
+ YYABORT;
+ };
opt_low_priority:
/* empty */ { $$= YYTHD->update_lock_default; }