Commit 886a35bd authored by unknown's avatar unknown

Bug#16461: connection_id() does not work properly inside trigger

CONNECTION_ID() was implemented as a constant Item, i.e. an instance of
Item_static_int_func class holding value computed at creation time.
Since Items are created on parsing, and trigger statements are parsed
on table open, the first connection to open a particular table would
effectively set its own CONNECTION_ID() inside trigger statements for
that table.

Re-implement CONNECTION_ID() as a class derived from Item_int_func, and
compute connection_id on every call to fix_fields().


mysql-test/r/trigger.result:
  Add result for bug#16461.
mysql-test/t/trigger.test:
  Add test case for bug#16461.
sql/item.cc:
  Remove now unused class Item_static_int_func.
sql/item.h:
  Remove now unused class Item_static_int_func.
sql/item_create.cc:
  Use new implementation of CONNECTION_ID().
sql/item_func.cc:
  Re-implement CONNECTION_ID() as Item_func_connection_id
  (was Item_static_int_func).  Set max_length to 10, as it was before.
  Compute connection_id dynamically on every call to fix_fields().
sql/item_func.h:
  Re-implement CONNECTION_ID() as Item_func_connection_id
  (was Item_static_int_func).
parent daac3886
......@@ -952,3 +952,16 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
drop table t1;
drop function f1;
drop function f2;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
conn_id INT,
trigger_conn_id INT
);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.trigger_conn_id = CONNECTION_ID();
INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1);
INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1);
SELECT * FROM t1 WHERE conn_id != trigger_conn_id;
conn_id trigger_conn_id
DROP TRIGGER t1_bi;
DROP TABLE t1;
......@@ -1114,3 +1114,31 @@ load data infile '../std_data_ln/words.dat' into table t1 (a) set b:= f1();
drop table t1;
drop function f1;
drop function f2;
#
# Test for Bug #16461 connection_id() does not work properly inside trigger
#
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (
conn_id INT,
trigger_conn_id INT
);
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.trigger_conn_id = CONNECTION_ID();
INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1);
connect (con1,localhost,root,,);
INSERT INTO t1 (conn_id, trigger_conn_id) VALUES (CONNECTION_ID(), -1);
connection default;
disconnect con1;
SELECT * FROM t1 WHERE conn_id != trigger_conn_id;
DROP TRIGGER t1_bi;
DROP TABLE t1;
# End of 5.0 tests
......@@ -644,22 +644,6 @@ Item *Item_num::safe_charset_converter(CHARSET_INFO *tocs)
}
Item *Item_static_int_func::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
char buf[64];
String *s, tmp(buf, sizeof(buf), &my_charset_bin);
s= val_str(&tmp);
if ((conv= new Item_static_string_func(func_name, s->ptr(), s->length(),
s->charset())))
{
conv->str_value.copy();
conv->str_value.mark_as_const();
}
return conv;
}
Item *Item_static_float_func::safe_charset_converter(CHARSET_INFO *tocs)
{
Item_string *conv;
......
......@@ -1387,18 +1387,6 @@ public:
};
class Item_static_int_func :public Item_int
{
const char *func_name;
public:
Item_static_int_func(const char *str_arg, longlong i, uint length)
:Item_int(NullS, i, length), func_name(str_arg)
{}
Item *safe_charset_converter(CHARSET_INFO *tocs);
void print(String *str) { str->append(func_name); }
};
class Item_uint :public Item_int
{
public:
......
......@@ -71,14 +71,8 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
thd->lex->safe_to_cache_query= 0;
return new Item_static_int_func("connection_id()",
(longlong)
((thd->slave_thread) ?
thd->variables.pseudo_thread_id :
thd->thread_id),
10);
current_thd->lex->safe_to_cache_query= 0;
return new Item_func_connection_id();
}
Item *create_func_conv(Item* a, Item *b, Item *c)
......
......@@ -559,6 +559,31 @@ String *Item_int_func::val_str(String *str)
}
void Item_func_connection_id::fix_length_and_dec()
{
Item_int_func::fix_length_and_dec();
max_length= 10;
}
bool Item_func_connection_id::fix_fields(THD *thd, Item **ref)
{
if (Item_int_func::fix_fields(thd, ref))
return TRUE;
/*
To replicate CONNECTION_ID() properly we should use
pseudo_thread_id on slave, which contains the value of thread_id
on master.
*/
value= ((thd->slave_thread) ?
thd->variables.pseudo_thread_id :
thd->thread_id);
return FALSE;
}
/*
Check arguments here to determine result's type for a numeric
function of two arguments.
......
......@@ -279,6 +279,18 @@ public:
};
class Item_func_connection_id :public Item_int_func
{
longlong value;
public:
const char *func_name() const { return "connection_id"; }
void fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
};
class Item_func_signed :public Item_int_func
{
public:
......
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