Re: Are functions evaluated before or during insertion?

2005-11-28 Thread sheeri kritzer
Hi Björn,

I tested what you did on one of my systems, running 4.0.20:

mysql create table parent (
-  ID int unsigned not null auto_increment,
-  value varchar(50),
-  primary key (ID)
- ) engine=InnoDB;

create table child (
 ID int unsigned not null auto_increment,
 parent_ID int unsigned not null,
 value varchar(50),
 primary key (ID),
 key (parent_ID),
 foreign key (parent_ID) references parent (ID)
) engine=InnoDB;

insert into parent (value) values ('a');Query OK, 0 rows affected (0.05 sec)

mysql
mysql create table child (
-  ID int unsigned not null auto_increment,
-  parent_ID int unsigned not null,
-  value varchar(50),
-  primary key (ID),
-  key (parent_ID),
-  foreign key (parent_ID) references parent (ID)
- ) engine=InnoDB;
Query OK, 0 rows affected (0.05 sec)

mysql
mysql insert into parent (value) values ('a');
Query OK, 1 row affected (0.02 sec)

mysql select last_insert_ID();   
+--+
| last_insert_id() |
+--+
|1 |
+--+
1 row in set (0.00 sec)

*this value is as
expected*

mysql insert into child (parent_ID, value) values (last_insert_ID(),
'b1'), (last_insert_ID(), 'b2'), (last_insert_ID(), 'b3');
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql select last_insert_ID();   
+--+
| last_insert_id() |
+--+
|1 |
+--+
1 row in set (0.00 sec)

*
this value is interesting -- we've inserted 3 items into the child
table, and the last_insert_ID() is still 1.  So I ran the command
again:
*

mysql insert into child (parent_ID, value) values (last_insert_ID(),
'b1'), (last_insert_ID(), 'b2'), (last_insert_ID(), 'b3');
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql select last_insert_ID();   
+--+
| last_insert_id() |
+--+
|4 |
+--+
1 row in set (0.00 sec)

*
this value is interesting also -- given these 2 results, MySQL only
finds the value for last_insert_ID once per statement, instead of once
per actual new row.  I have 6 rows in my table, and the last_insert_id
is 4.
*

mysql insert into child (parent_ID, value) values (last_insert_ID(),
'b1'), (last_insert_ID(), 'b2'), (last_insert_ID(), 'b3');
ERROR 1216: Cannot add or update a child row: a foreign key constraint fails
mysql select last_insert_ID();   
+--+
| last_insert_id() |
+--+
|7 |
+--+
1 row in set (0.00 sec)

mysql select * from child;
++---+---+
| ID | parent_ID | value |
++---+---+
|  1 | 1 | b1|
|  2 | 1 | b2|
|  3 | 1 | b3|
|  4 | 1 | b1|
|  5 | 1 | b2|
|  6 | 1 | b3|
++---+---+
6 rows in set (0.00 sec)

*
This makes sense, because it's trying to insert a parent_ID of 4,
which is the current value of last_insert_id.  Nothing was inserted,
and yet the last_insert_ID() changed to 7, even though it didn't even
insert anything with the value of 7 into the child table.

Granted, I tested this on MySQL 4.0.20, but it seems consistent with
what you get.  As well, if you're inserting multiple parent rows, the
last_insert_ID is the first ID that is inserted:

mysql insert into parent (value) VALUES ('b'),('c'),('d');
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql select last_insert_ID();
+--+
| last_insert_id() |
+--+
|2 |
+--+
1 row in set (0.00 sec)

mysql select * from parent;
++---+
| ID | value |
++---+
|  1 | a |
|  2 | b |
|  3 | c |
|  4 | d |
++---+
4 rows in set (0.00 sec)

We would expect the value of last_insert_ID() to be 4, not 2.

I had to dig into the documentation to find this, but it's in there:

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html

LAST_INSERT_ID()  LAST_INSERT_ID(expr)

Returns the first automatically generated value that was set for an
AUTO_INCREMENT column by the last INSERT or UPDATE query to affect
such a column.

-Sheeri

On 11/4/05, Björn Persson [EMAIL PROTECTED] wrote:
 Hi everybody!

 It seems like different instances of MySQL do things in different order, with
 rather unfortunate effects on the last_insert_ID function.

 Consider the following tables and insertions:

 create table parent (
   ID int unsigned not null auto_increment,
   value varchar(50),
   primary key 

Are functions evaluated before or during insertion?

2005-11-04 Thread Björn Persson
Hi everybody!

It seems like different instances of MySQL do things in different order, with 
rather unfortunate effects on the last_insert_ID function.

Consider the following tables and insertions:

create table parent (
  ID int unsigned not null auto_increment,
  value varchar(50),
  primary key (ID)
) engine=InnoDB;

create table child (
  ID int unsigned not null auto_increment,
  parent_ID int unsigned not null,
  value varchar(50),
  primary key (ID),
  key (parent_ID),
  foreign key (parent_ID) references parent (ID)
) engine=InnoDB;

insert into parent (value) values ('a');

insert into child (parent_ID, value) values 
(last_insert_ID(), 'b1'), (last_insert_ID(), 'b2'), (last_insert_ID(), 'b3');

The intention is of course that all three child rows should reference the 
parent row that was inserted. This will work if the server first evaluates 
all the calls to last_insert_ID and then starts inserting the rows. I have 
one MySQL 4.0 server where this appears to work consistently.

On some MySQL 4.1 servers I sometimes get the error a foreign key constraint 
fails. On one server it sometimes works and sometimes not. What I think 
happens is that the server evaluates the first call to last_insert_ID and 
inserts the first row (b1), and then starts processing the b2 row, evaluates 
last_insert_ID again, and gets the ID of the b1 row.

I thought I had read somewhere in the documentation that functions are 
evaluated before data is inserted, and as this never failed on my development 
server I relied on it. Then it failed on the production server. Ouch!

So my questions are:
1: Is this expected behaviour? That is, should I expect some function calls to 
be evaluated after some rows have already been inserted and auto_increment 
counters have been incremented, or are functions supposed to be evaluated 
before insertion starts?
2: Whichever order a query is processed in, wouldn't it be better to always do 
things in the same order?

Björn Persson

--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/[EMAIL PROTECTED]