Commit df064669 authored by unknown's avatar unknown

Fixed BUG#3117: LAST_INSERT_ID() works incorrectly inside stored procedure.

This turned out to be a problem for prepared statements as well; the id was
evaluated once, at parse time.


mysql-test/r/auto_increment.result:
  Updated results after bugfix in last_insert_id().
mysql-test/r/query_cache.result:
  Updated results after bugfix in last_insert_id().
mysql-test/r/variables.result:
  Updated results after bugfix in last_insert_id().
sql/item_func.cc:
  Fixed bug in last_insert_id(); get id at each evaluation (and not in the parser).
  Renamed the class Item_func_set_last_insert_id too, since it's not only for setting.
sql/item_func.h:
  Fixed bug in last_insert_id(); get id at each evaluation (and not in the parser).
  Renamed the class Item_func_set_last_insert_id too, since it's not only for setting.
sql/sql_yacc.yy:
  Fixed bug in last_insert_id(); get id at each evaluation (and not in the parser).
  Renamed the class Item_func_set_last_insert_id too, since it's not only for setting.
tests/client_test.c:
  Test case for last_insert_id() in prepared statements.
parent d8c53581
...@@ -142,7 +142,7 @@ explain extended select last_insert_id(); ...@@ -142,7 +142,7 @@ explain extended select last_insert_id();
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings: Warnings:
Note 1003 select high_priority no_cache 255 AS `last_insert_id()` Note 1003 select high_priority no_cache last_insert_id() AS `last_insert_id()`
insert into t1 set i = 254; insert into t1 set i = 254;
ERROR 23000: Duplicate entry '254' for key 1 ERROR 23000: Duplicate entry '254' for key 1
select last_insert_id(); select last_insert_id();
......
...@@ -292,7 +292,7 @@ DATABASE() ...@@ -292,7 +292,7 @@ DATABASE()
select ENCRYPT("test") from t1; select ENCRYPT("test") from t1;
ENCRYPT("test") ENCRYPT("test")
select LAST_INSERT_ID() from t1; select LAST_INSERT_ID() from t1;
last_insert_id() LAST_INSERT_ID()
select RAND() from t1; select RAND() from t1;
RAND() RAND()
select UNIX_TIMESTAMP() from t1; select UNIX_TIMESTAMP() from t1;
......
...@@ -93,7 +93,7 @@ explain extended select @@IDENTITY,last_insert_id(), @@identity; ...@@ -93,7 +93,7 @@ explain extended select @@IDENTITY,last_insert_id(), @@identity;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings: Warnings:
Note 1003 select high_priority no_cache 345 AS `@@IDENTITY`,345 AS `last_insert_id()`,345 AS `@@identity` Note 1003 select high_priority no_cache 345 AS `@@IDENTITY`,last_insert_id() AS `last_insert_id()`,345 AS `@@identity`
set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON";
set global concurrent_insert=ON; set global concurrent_insert=ON;
show variables like 'concurrent_insert'; show variables like 'concurrent_insert';
......
...@@ -2139,13 +2139,22 @@ longlong Item_func_release_lock::val_int() ...@@ -2139,13 +2139,22 @@ longlong Item_func_release_lock::val_int()
} }
longlong Item_func_set_last_insert_id::val_int() longlong Item_func_last_insert_id::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (arg_count)
{
longlong value=args[0]->val_int(); longlong value=args[0]->val_int();
current_thd->insert_id(value); current_thd->insert_id(value);
null_value=args[0]->null_value; null_value=args[0]->null_value;
return value; return value;
}
else
{
Item *it= get_system_var(current_thd, OPT_SESSION, "last_insert_id", 14,
"last_insert_id()");
return it->val_int();
}
} }
/* This function is just used to test speed of different functions */ /* This function is just used to test speed of different functions */
......
...@@ -729,13 +729,14 @@ public: ...@@ -729,13 +729,14 @@ public:
}; };
class Item_func_set_last_insert_id :public Item_int_func class Item_func_last_insert_id :public Item_int_func
{ {
public: public:
Item_func_set_last_insert_id(Item *a) :Item_int_func(a) {} Item_func_last_insert_id() :Item_int_func() {}
Item_func_last_insert_id(Item *a) :Item_int_func(a) {}
longlong val_int(); longlong val_int();
const char *func_name() const { return "last_insert_id"; } const char *func_name() const { return "last_insert_id"; }
void fix_length_and_dec() { max_length=args[0]->max_length; } void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; }
}; };
class Item_func_benchmark :public Item_int_func class Item_func_benchmark :public Item_int_func
......
...@@ -2750,13 +2750,12 @@ simple_expr: ...@@ -2750,13 +2750,12 @@ simple_expr:
} }
| LAST_INSERT_ID '(' ')' | LAST_INSERT_ID '(' ')'
{ {
$$= get_system_var(YYTHD, OPT_SESSION, "last_insert_id", 14, $$= new Item_func_last_insert_id();
"last_insert_id()");
Lex->safe_to_cache_query= 0; Lex->safe_to_cache_query= 0;
} }
| LAST_INSERT_ID '(' expr ')' | LAST_INSERT_ID '(' expr ')'
{ {
$$= new Item_func_set_last_insert_id($3); $$= new Item_func_last_insert_id($3);
Lex->safe_to_cache_query= 0; Lex->safe_to_cache_query= 0;
} }
| LEFT '(' expr ',' expr ')' | LEFT '(' expr ',' expr ')'
......
...@@ -8377,6 +8377,68 @@ static void test_subqueries_ref() ...@@ -8377,6 +8377,68 @@ static void test_subqueries_ref()
myquery(rc); myquery(rc);
} }
static void test_bug3117()
{
MYSQL_STMT *stmt;
MYSQL_BIND buffer;
longlong lii;
ulong length;
my_bool is_null;
int rc;
myheader("test_bug3117");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql,"CREATE TABLE t1 (id int auto_increment primary key)");
myquery(rc);
stmt = mysql_simple_prepare(mysql, "SELECT LAST_INSERT_ID()");
mystmt_init(stmt);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
myquery(rc);
rc = mysql_execute(stmt);
mystmt(stmt,rc);
buffer.buffer_type= MYSQL_TYPE_LONGLONG;
buffer.buffer_length= sizeof(lii);
buffer.buffer= (char *)&lii;
buffer.length= &length;
buffer.is_null= &is_null;
rc= mysql_bind_result(stmt, &buffer);
mystmt(stmt,rc);
rc= mysql_stmt_store_result(stmt);
mystmt(stmt,rc);
rc = mysql_fetch(stmt);
mystmt(stmt, rc);
assert(is_null == 0 && lii == 1);
fprintf(stdout, "\n\tLAST_INSERT_ID() = 1 ok\n");
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (NULL)");
myquery(rc);
rc = mysql_execute(stmt);
mystmt(stmt,rc);
rc = mysql_fetch(stmt);
mystmt(stmt, rc);
assert(is_null == 0 && lii == 2);
fprintf(stdout, "\tLAST_INSERT_ID() = 2 ok\n");
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1");
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -8634,8 +8696,7 @@ int main(int argc, char **argv) ...@@ -8634,8 +8696,7 @@ int main(int argc, char **argv)
test_distinct(); /* distinct aggregate functions */ test_distinct(); /* distinct aggregate functions */
test_subqueries_ref(); /* outer reference in subqueries converted test_subqueries_ref(); /* outer reference in subqueries converted
Item_field -> Item_ref */ Item_field -> Item_ref */
test_bug3117(); /* BUG#3117: LAST_INSERT_ID() */
end_time= time((time_t *)0); end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time); total_time+= difftime(end_time, start_time);
......
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