Bug #9486 can't perform multi-update in stored procedure

Submitted: 30 Mar 2005 13:58 Modified: 14 Jun 2005 7:18
Reporter: Dmitry L Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:5.0.3 OS:Windows (Win2k)
Assigned to: Dmitry Lenev CPU Architecture:Any

[30 Mar 2005 13:58] Dmitry L
Description:
Can't perform update inside stored procedure:
Error is: "Table 'op' was locked with a READ lock and can't be updated"

How to repeat:
here's procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `parallax_kernel`.`updateTitles`$$
CREATE PROCEDURE `parallax_kernel`.`updateTitles`(OUT affected INT)
BEGIN
  UPDATE objects_path op,
         objects_hier oh
     SET op.title = oh.title
   WHERE op.pid = oh.id
     AND op.map = oh.map;
  SELECT ROW_COUNT() INTO affected;
END$$
DELIMITER ;

Tables:
CREATE TABLE `objects_path` (
  `id` int(10) unsigned NOT NULL default '0',
  `pid` int(10) unsigned NOT NULL default '0',
  `map` smallint(6) unsigned NOT NULL default '0',
  `level` tinyint(4) unsigned NOT NULL default '0',
  `title` varchar(255) default NULL,
  PRIMARY KEY  (`id`,`map`,`level`),
  KEY `pid` (`pid`),
  KEY `level` (`level`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `objects_hier` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `pid` int(10) unsigned NOT NULL default '0',
  `flags_0` int(10) unsigned NOT NULL default '0',
  `flags_1` int(10) unsigned NOT NULL default '0',
  `flags_2` int(10) unsigned NOT NULL default '0',
  `proto` smallint(6) unsigned NOT NULL default '0',
  `sort` smallint(6) NOT NULL default '0',
  `template` int(10) unsigned default NULL,
  `map` smallint(6) unsigned NOT NULL default '0',
  `mapped_from` smallint(6) unsigned default NULL,
  `lnk4` int(10) unsigned default NULL,
  `crt` double(15,4) unsigned NOT NULL default '0.0000',
  `mdf` double(15,4) unsigned NOT NULL default '0.0000',
  `path` bigint(20) unsigned default NULL,
  `owner` int(10) unsigned default NULL,
  `size` int(10) unsigned NOT NULL default '100',
  `title` varchar(255) default NULL,
  `remark` varchar(255) default NULL,
  `xml` mediumtext,
  PRIMARY KEY  (`id`,`map`),
  KEY `proto` (`proto`),
  KEY `title` (`title`),
  KEY `pid` (`pid`),
  KEY `id` (`id`,`mapped_from`),
  KEY `lnk4` (`lnk4`,`map`),
  KEY `sort` (`sort`),
  KEY `path` (`path`),
  KEY `owner` (`owner`),
  KEY `size` (`size`),
  KEY `template` (`template`,`map`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Call is:
call updateTitles(@a);

There are no active locks and opened transactions on the server and call is done by @root
[9 Apr 2005 12:05] Dmitry Lenev
Please also note that second invocation of updateTitles() will block current connection...
[14 Apr 2005 4:51] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/24000
[15 Apr 2005 16:30] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/24057
[22 Apr 2005 8:32] Dmitry Lenev
Fixed in 5.0.5
[26 Apr 2005 3:10] Paul DuBois
Noted in 5.0.5 changelog.
[14 Jun 2005 0:12] Peter Brawley
This bug persists in 5.0.6, as the following script shows:

CREATE TABLE airports (
code char(3) NOT NULL,
city char(100) default NULL,
latitude float NOT NULL,
longitude float NOT NULL,
PRIMARY KEY (code)
) ENGINE=MyISAM;

INSERT INTO airports VALUES ('JFK', 'New York, NY', 40.75, -73.97);
INSERT INTO airports VALUES ('LAX', 'Los Angeles, CA', 34.05, -118.22);
INSERT INTO airports VALUES ('LHR', 'London, England', 51.5, -0.45);
INSERT INTO airports VALUES ('HEL', 'Helsinki, Finland', 60.17, 24.97);
INSERT INTO airports VALUES ('CDG', 'Paris, France', 48.86, 2.33);
INSERT INTO airports VALUES ('STL', 'St Louis, MO', 38.63, -90.2);
INSERT INTO airports VALUES ('ARN', 'Stockholm, Sweden', 59.33, 18.05); 

-- Workaround for another bug
SET GLOBAL log_bin_trust_routine_creators=TRUE; 

DROP FUNCTION IF EXISTS GeoDistKM; 
DELIMITER |
CREATE FUNCTION GeoDistKM( lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT ) RETURNS float
BEGIN
  DECLARE pi, q1, q2, q3 FLOAT;
  DECLARE rads FLOAT DEFAULT 0;
  SET pi = PI();
  SET lat1 = lat1 * pi / 180;
  SET lon1 = lon1 * pi / 180;
  SET lat2 = lat2 * pi / 180;
  SET lon2 = lon2 * pi / 180;
  SET q1 = COS(lon1-lon2);
  SET q2 = COS(lat1-lat2);
  SET q3 = COS(lat1+lat2);
  SET rads = ACOS( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) ); 
  RETURN 6378.388 * rads;
END;
|
DELIMITER ; 

CREATE TABLE flights (
  id INT PRIMARY KEY AUTO_INCREMENT,
  depart CHAR(3),
  arrive CHAR(3),
  distance DECIMAL(10,2),
  direction DECIMAL(10,2)
) ENGINE=MYISAM;

INSERT INTO flights
  SELECT
  NULL,
  depart.code,
  arrive.code,
 ROUND(GeoDistKM(depart.latitude,depart.longitude,arrive.latitude,arrive.longitude),2) AS Km,
  ROUND(DEGREES(ATAN(arrive.latitude-depart.latitude,arrive.longitude-depart.longitude)),2)
  FROM airports AS depart
  INNER JOIN airports AS arrive ON depart.code <> arrive.code
  HAVING Km <= 6000;
  
CREATE TABLE routes (
  id INT PRIMARY KEY AUTO_INCREMENT,
  depart CHAR(3),
  arrive CHAR(3),
  hops SMALLINT,
  route CHAR(50),
  distance DECIMAL(10,2),
  direction DECIMAL(10,2)
) ENGINE=MYISAM; 

CREATE OR REPLACE VIEW nexthops AS
  SELECT 
    routes.depart,
    flights.arrive,
    routes.hops+1 AS hops,
    CONCAT(routes.route, ',', flights.arrive) AS route,
    MIN(routes.distance + flights.distance) AS distance,
    routes.direction
  FROM routes INNER JOIN flights 
    ON routes.arrive = flights.depart
    AND LOCATE(flights.arrive,routes.route) = 0
  WHERE flights.direction+360>routes.direction+270 
    AND flights.direction+360<routes.direction+450
  GROUP BY depart,arrive;
  
SET GLOBAL log_bin_trust_routine_creators=TRUE; 
DROP PROCEDURE IF EXISTS BuildRoutes;
DELIMITER |
CREATE PROCEDURE BuildRoutes()
BEGIN
  DECLARE rows INT DEFAULT 0;
  TRUNCATE routes;

  -- STEP 1, LISTING 5: SEED ROUTES WITH 1-HOP FLIGHTS
  INSERT INTO routes
    SELECT 
      NULL,
      depart,
      arrive,
      1,
      CONCAT(depart,',',arrive),
      distance,
      direction
  FROM flights;
  SET rows = ROW_COUNT();

  WHILE (rows > 0) DO

    -- STEP 2, LISTING 8: ADD NEXT SET OF ROUTES
    INSERT INTO routes
      SELECT 
        NULL,
        nexthops.depart,
        nexthops.arrive,
        nexthops.hops,
        nexthops.route,
        nexthops.distance,
        nexthops.direction 
      FROM nexthops
      LEFT JOIN routes ON nexthops.depart = routes.depart 
            AND nexthops.arrive = routes.arrive
      WHERE routes.depart IS NULL AND routes.arrive IS NULL;
    SET rows = ROW_COUNT();

  END WHILE;

END;
|
DELIMITER ;

ERROR 1099 (HY000): Table 'routes' was locked with a READ lock and can't be updated
[14 Jun 2005 7:18] Dmitry Lenev
Hi, Peter!

Original problem mentioned in this bug report was impossibility to perform multi-update in  stored procedure due to problem with table locking (I have updated synopsis to clarify this). 

After investigating your issue I think that your problem has nothing to do with original one so it should be reported and handled separately. And as I've noticed you already have done that! :)

Thank you!

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.041 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.