2011-02-16 68 views
5

我想有人试图模拟有第二个auto_increment值。刚刚升级到MySQL 5.5.9为什么这个MySQL触发器会导致堆栈溢出?

CREATE TABLE `job_title` (
    `job_id` int(11) NOT NULL AUTO_INCREMENT, 
    `position_id` int(11) DEFAULT NULL, 
    `title` varchar(255) COLLATE latin1_general_cs NOT NULL, 
    `selectable` tinyint(4) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`job_id`), 
    UNIQUE KEY `title` (`title`) 
) ENGINE=InnoDB; 

create trigger job_position_trigger 
    before insert on job_title for each row 
begin 
    if new.position_id is null then 
    set @position = (select max(position_id)+1 from job_title); 
    set new.position_id = @position; 
    end if; 
end 

错误:Thread stack overrun: 9024 bytes used of a 131072 byte stack, and 128000 bytes needed. Use 'mysqld --thread_stack=#' to specify a bigger stack.' on query. Default database: 'mydb'. Query: 'insert ignore into job_title (title) values ('Morning Show Personality')

+0

我跑了它没有抱怨 – RichardTheKiwi

+0

工作的同样的东西你使用的是MySQL 5.5吗? –

+2

@nick酷名:) –

回答

1

在MySQL 5.1中我无法引起溢出堆栈,但[position_id]字段从未被触发设置。它从来没有设置的原因是,当你在空表上执行MAX(position_id)+ 1或在[position_id]列中只有NULL时,你的@position变量将被设置为NULL。我不知道这是否导致触发器重新评估自己(看到[position_id]仍然为空),所以它反复调用自己导致堆栈溢出。您可以尝试的一种方法是更改​​触发器以检查null @position值,并在分配值之前将其强制为“1”。

create trigger job_position_trigger 
    before insert on job_title for each row 
begin  
    if new.position_id is null then  
     set @position = (select max(position_id)+1 from job_title); 
     if @position is null then set @position = 1; end if; 
     set new.position_id = @position;  
    end if; 
end; 
+0

这是我的第一个想法。 – Ben

10

今天我遇到了同样的问题,每次触发都会导致堆栈溢出。原来我的Zend社区服务器安装附带了其中thread_stack大小设置为128K默认的my.cnf文件,导致可用于堆栈中的每个线程131072个字节:

mysql> show variables where `Variable_name` = 'thread_stack'; 
+---------------+--------+ 
| Variable_name | Value | 
+---------------+--------+ 
| thread_stack | 131072 | 
+---------------+--------+ 

所以我注释掉在/usr/local/zend/mysql/data/my.cnf行,重新启动mysql守护进程,瞧!该default 192K是

mysql> show variables where `Variable_name` = 'thread_stack'; 
+---------------+--------+ 
| Variable_name | Value | 
+---------------+--------+ 
| thread_stack | 196608 | 
+---------------+--------+ 

现在你的表& tchester的触发工作完美:)(千万注意虽然分隔符)

mysql> CREATE TABLE `job_title` (
    -> `job_id` int(11) NOT NULL AUTO_INCREMENT, 
    -> `position_id` int(11) DEFAULT NULL, 
    -> `title` varchar(255) COLLATE latin1_general_cs NOT NULL, 
    -> `selectable` tinyint(4) NOT NULL DEFAULT '0', 
    -> PRIMARY KEY (`job_id`), 
    -> UNIQUE KEY `title` (`title`) 
    ->) ENGINE=InnoDB; 
Query OK, 0 rows affected (0.14 sec) 

mysql> DELIMITER && 
mysql> create trigger job_position_trigger 
    -> before insert on job_title for each row 
    -> begin  
    ->  if new.position_id is null then  
    ->  set @position = (select max(position_id)+1 from job_title); 
    ->  if @position is null then set @position = 1; end if; 
    ->  set new.position_id = @position;  
    ->  end if; 
    -> end; 
    -> && 
Query OK, 0 rows affected (0.29 sec) 

mysql> DELIMITER ; 
mysql> insert into job_title (title, selectable) values ("test", 1); 
Query OK, 1 row affected (0.00 sec) 

mysql> insert into job_title (title, selectable) values ("test2", 3); 
Query OK, 1 row affected (0.00 sec) 

mysql> select * from job_title; 
+--------+-------------+-------+------------+ 
| job_id | position_id | title | selectable | 
+--------+-------------+-------+------------+ 
|  1 |   1 | test |   1 | 
|  2 |   2 | test2 |   3 | 
+--------+-------------+-------+------------+ 
2 rows in set (0.00 sec) 

你得到了错误,使用了131072字节堆栈的9024个字节, 128000字节需要,是有道理的:9024 + 128000> 131072.