r4083 bugfix: prevent invalid port links (#363), remove DB triggers
authorAaron Dummer <aaron@dummer.info>
Sat, 8 Jan 2011 19:14:35 +0000 (19:14 +0000)
committerAaron Dummer <aaron@dummer.info>
Sat, 8 Jan 2011 19:14:35 +0000 (19:14 +0000)
install/init-structure.sql: remove triggers
executeUpgradeBatch(): idem
isInnoDBSupported(): idem
linkPorts(): add SELECT before INSERT check

ChangeLog
README
inc/database.php
inc/dictionary.php
install/init-structure.sql
upgrade.php

index 74a5a70..9cf9407 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,7 +11,7 @@
        bugfix: UI: pager in ipv4net shows appropriate page when IP is highlighted
        bugfix: create IPv4 network button, if pressed to open in a new window, was redirecting the parent window, too
        bugfix: when searching for IP not belonging to any known network, the ugly assertion failed page was shown.
-       bugfix: add DB triggers to prevent invalid port links (#363, by Aaron Dummer)
+       bugfix: prevent invalid port links (#363, by Aaron Dummer)
        update: links to ports added to object search results
        update: custom rearch results provided by users' plugins now supported
        new feature: syncdomain.php now can create child processes to speed up 802.1Q sync
diff --git a/README b/README
index 128c122..6416089 100644 (file)
--- a/README
+++ b/README
@@ -100,9 +100,6 @@ should be sufficient:
 
 *** Upgrading to 0.19.x ***
 
-This release utilizes database triggers, which are only available in
-MySQL >= 5.0.2.
-
 RackTables is now using PHP JSON extension which is included in the PHP core since 5.2.0.
 Installation process does not check for this extension because the lack of it does not affect
 base functionality. If some of ajax features are not working correctly, check if JSON extension
index 5dcec52..6612a2a 100644 (file)
@@ -1018,6 +1018,19 @@ function linkPorts ($porta, $portb, $cable = NULL)
 {
        if ($porta == $portb)
                throw new InvalidArgException ('porta/portb', $porta, "Ports can't be the same");
+
+       global $dbxlink;
+       $dbxlink->exec ('LOCK TABLES Link WRITE');
+       $result = usePreparedSelectBlade
+       (
+               'SELECT COUNT(*) FROM Link WHERE porta IN (?,?) OR portb IN (?,?)',
+               array ($porta, $portb, $porta, $portb)
+       );
+       if ($result->fetchColumn () != 0)
+       {
+               $dbxlink->exec ('UNLOCK TABLES');               
+               return "Port ${porta} or ${portb} is already linked";
+       }
        if ($porta > $portb)
        {
                $tmp = $porta;
@@ -1025,6 +1038,7 @@ function linkPorts ($porta, $portb, $cable = NULL)
                $portb = $tmp;
        }
        $ret = FALSE !== usePreparedInsertBlade ('Link', array ('porta' => $porta, 'portb' => $portb, 'cable' => $cable));
+       $dbxlink->exec ('UNLOCK TABLES');
        $ret = $ret and FALSE !== usePreparedExecuteBlade
        (
                'UPDATE Port SET reservation_comment=NULL WHERE id IN(?, ?)',
index 6fcad22..ab859b3 100644 (file)
@@ -26,12 +26,9 @@ function isInnoDBSupported ()
        global $dbxlink;
        // create a temp table
        $dbxlink->query("CREATE TABLE `innodb_test` (`id` int) ENGINE=InnoDB");
-       $innodb_row = $dbxlink->query("SHOW TABLE STATUS LIKE 'innodb_test'")->fetch(PDO::FETCH_ASSOC);
-       // create a trigger
-       $dbxlink->query("CREATE TRIGGER `trigger_test` BEFORE INSERT ON `innodb_test` FOR EACH ROW BEGIN END");
-       $trigger_row = $dbxlink->query("SELECT COUNT(*) AS count FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = SCHEMA() AND TRIGGER_NAME = 'trigger_test'")->fetch(PDO::FETCH_ASSOC);
+       $row = $dbxlink->query("SHOW TABLE STATUS LIKE 'innodb_test'")->fetch(PDO::FETCH_ASSOC);
        $dbxlink->query("DROP TABLE `innodb_test`");
-       if ($innodb_row['Engine'] == 'InnoDB' && $trigger_row['count'] == 1)
+       if ($row['Engine'] == 'InnoDB')
                return TRUE;
 
        return FALSE;
index df77188..a1b4a62 100644 (file)
@@ -250,42 +250,6 @@ CREATE TABLE `Link` (
   CONSTRAINT `Link-FK-b` FOREIGN KEY (`portb`) REFERENCES `Port` (`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB;
 
-DELIMITER ;;
-CREATE TRIGGER `checkForDuplicateLinksBeforeInsert` BEFORE INSERT ON `Link`
-  FOR EACH ROW
-BEGIN
-  DECLARE count INTEGER;
-
-  IF NEW.porta = NEW.portb THEN
-    SET NEW.porta = NULL;
-  END IF;
-
-  SELECT COUNT(*) INTO count FROM Link WHERE porta IN (NEW.porta,NEW.portb) OR portb IN (NEW.porta,NEW.portb);
-
-  IF count > 0 THEN
-    SET NEW.porta = NULL;
-  END IF;
-END;;
-
-CREATE TRIGGER `checkForDuplicateLinksBeforeUpdate` BEFORE UPDATE ON `Link`
-  FOR EACH ROW
-BEGIN
-  DECLARE count INTEGER;
-
-  IF NEW.porta = NEW.portb THEN
-    SET NEW.porta = NULL;
-  END IF;
-
-  SELECT COUNT(*) INTO count FROM Link WHERE
-  (NEW.porta IN (porta,portb) AND NEW.porta != porta) OR
-  (NEW.portb IN (porta,portb) AND NEW.portb != portb);
-  IF count > 0 THEN
-    SET NEW.porta = NULL;
-  END IF;
-END;;
-DELIMITER ;
-
 CREATE TABLE `Molecule` (
   `id` int(10) unsigned NOT NULL auto_increment,
   PRIMARY KEY  (`id`)
index 899c512..90bd788 100644 (file)
@@ -756,23 +756,6 @@ CREATE TABLE `VLANValidID` (
                        $query[] = "UPDATE Config SET varvalue = '0.18.5' WHERE varname = 'DB_VERSION'";
                        break;
                case '0.19.0':
-                       if (!isInnoDBSupported ())
-                       {
-                               showFailure ("Cannot upgrade because triggers are not supported by your MySQL server.", __FILE__);
-                               die;
-                       }
-
-                       // search for invalid Links
-                       $result = $dbxlink->query ("SELECT * FROM Link WHERE porta=portb OR porta IN (SELECT portb FROM Link) OR portb IN (SELECT porta FROM Link);");
-                       $rows = $result->fetchAll (PDO::FETCH_ASSOC);
-                       if (count($rows) > 0)
-                       {
-                               foreach ($rows as $row)
-                                       $invalid_msg .= sprintf("porta: %s, portb: %s\n", $row['porta'], $row['portb']);
-                               showFailure("Cannot upgrade because one or more invalid port links exist:\n{$invalid_msg}", __FILE__);
-                               die;    
-                       }
-
                        $query[] = 'ALTER TABLE `File` ADD `thumbnail` LONGBLOB NULL AFTER `atime`';
                        $query[] = "
 CREATE TABLE `IPv6Address` (
@@ -827,42 +810,6 @@ CREATE TABLE `ObjectLog` (
   KEY `date` (`date`),
   CONSTRAINT `ObjectLog-FK-object_id` FOREIGN KEY (`object_id`) REFERENCES `RackObject` (`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB
-";
-                       $query[] = "
-CREATE TRIGGER `checkForDuplicateLinksBeforeInsert` BEFORE INSERT ON `Link`
-  FOR EACH ROW
-BEGIN
-  DECLARE count INTEGER;
-
-  IF NEW.porta = NEW.portb THEN
-    SET NEW.porta = NULL;
-  END IF;
-
-  SELECT COUNT(*) INTO count FROM Link WHERE porta IN (NEW.porta,NEW.portb) OR portb IN (NEW.porta,NEW.portb);
-
-  IF count > 0 THEN
-    SET NEW.porta = NULL;
-  END IF;
-END;
-";
-                       $query[] = "
-CREATE TRIGGER `checkForDuplicateLinksBeforeUpdate` BEFORE UPDATE ON `Link`
-  FOR EACH ROW
-BEGIN
-  DECLARE count INTEGER;
-
-  IF NEW.porta = NEW.portb THEN
-    SET NEW.porta = NULL;
-  END IF;
-
-  SELECT COUNT(*) INTO count FROM Link WHERE
-  (NEW.porta IN (porta,portb) AND NEW.porta != porta) OR
-  (NEW.portb IN (porta,portb) AND NEW.portb != portb);
-  IF count > 0 THEN
-    SET NEW.porta = NULL;
-  END IF;
-END;
 ";
                        $query[] = "ALTER TABLE `TagStorage` CHANGE COLUMN `entity_realm` `entity_realm` ENUM('file','ipv4net','ipv4vs','ipv4rspool','object','rack','user','ipv6net') NOT NULL DEFAULT 'object' FIRST";
                        $query[] = "ALTER TABLE `FileLink` CHANGE COLUMN `entity_type` `entity_type` ENUM('ipv4net','ipv4rspool','ipv4vs','object','rack','user','ipv6net') NOT NULL DEFAULT 'object' AFTER `file_id`";