Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this MySQL trigger cause a stack overflow?

I think someone was trying to simulate having a second auto_increment value. Just upgraded to MySQL 5.5.9

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

The error: 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')

like image 863
ʞɔıu Avatar asked Feb 16 '11 20:02

ʞɔıu


People also ask

What happens if MySQL trigger fails?

If a BEFORE trigger fails, the operation on the corresponding row is not performed. A BEFORE trigger is activated by the attempt to insert or modify the row, regardless of whether the attempt subsequently succeeds. An AFTER trigger is executed only if any BEFORE triggers and the row operation execute successfully.

What is triggering in MySQL?

A trigger is defined to activate when a statement inserts, updates, or deletes rows in the associated table. These row operations are trigger events. For example, rows can be inserted by INSERT or LOAD DATA statements, and an insert trigger activates for each inserted row.

Why use MySQL triggers?

Advantages of triggers Triggers handle errors from the database layer. Triggers give an alternative way to run scheduled tasks. By using triggers, you don't have to wait for the scheduled events to run because the triggers are invoked automatically before or after a change is made to the data in a table.

Why we use each row in trigger?

The FOR EACH ROW option determines whether the trigger is a row trigger or a statement trigger. If you specify FOR EACH ROW , then the trigger fires once for each row of the table that is affected by the triggering statement.


1 Answers

I ran into the same problem today, every trigger causing a stack overrun. Turned out my Zend Community Server installation comes with a default my.cnf file in which the thread_stack size was set to 128K, which resulted in 131072 bytes available for the stack in each thread:

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

So I commented out the line in /usr/local/zend/mysql/data/my.cnf, restarted the mysql daemon, and voila! The default 192K is

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

Now your table & tchester's trigger work perfectly :) (do note the delimiter though)

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)

The error you got, 9024 bytes used of a 131072 byte stack, and 128000 bytes needed, makes sense: 9024 + 128000 > 131072.

like image 167
drvdijk Avatar answered Oct 31 '22 11:10

drvdijk