r2950 - l2address index isn't UNIQUE any more
authorDenis Ovsienko <infrastation@yandex.ru>
Wed, 15 Jul 2009 21:20:42 +0000 (21:20 +0000)
committerDenis Ovsienko <infrastation@yandex.ru>
Wed, 15 Jul 2009 21:20:42 +0000 (21:20 +0000)
 - alreadyUsedL2Address(): new function implements application-level constraint on l2address
 - commitAddPort(): do atomic INSERT combined with constraint check
 - commitUpdatePort(): idem

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

index 7214d33..708d807 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,7 @@
        update: add Cisco dictionary entry for WS-CBS3030-DEL. closes ticket 225 (by jthurman)
        update: add OS, router, fibre switch dictionary entries for ticket 238 (by Aaron)
        update: allow variations of FC WWN as an L2 address (by killsystem)
+       update: port L2 address can be reused on the same object
        bugfix: do not produce PHP warning on LivePTR tab
        bugfix: wrong port type set for WS-C2950-24. closes ticket 229 (by jthurman)
        bugfix: improved IOS detection and fixed a logic error. closes ticket 232 (by jthurman)
index 879e056..40c8184 100644 (file)
@@ -958,6 +958,13 @@ function commitAddPort ($object_id = 0, $port_name, $port_type_id, $port_label,
 {
        if (NULL === ($db_l2address = l2addressForDatabase ($port_l2address)))
                return "Invalid L2 address ${port_l2address}";
+       global $dbxlink;
+       $dbxlink->exec ('LOCK TABLES Port WRITE');
+       if (alreadyUsedL2Address ($db_l2address, $object_id))
+       {
+               $dbxlink->exec ('UNLOCK TABLES');
+               return "address ${db_l2address} belongs to another object";
+       }
        $result = useInsertBlade
        (
                'Port',
@@ -970,6 +977,7 @@ function commitAddPort ($object_id = 0, $port_name, $port_type_id, $port_label,
                        'l2address' => ($db_l2address === '') ? 'NULL' : "'${db_l2address}'"
                )
        );
+       $dbxlink->exec ('UNLOCK TABLES');
        if ($result)
                return '';
        else
@@ -984,12 +992,20 @@ function commitUpdatePort ($port_id, $port_name, $port_type_id, $port_label, $po
        global $dbxlink;
        if (NULL === ($db_l2address = l2addressForDatabase ($port_l2address)))
                return "Invalid L2 address ${port_l2address}";
+       global $dbxlink;
+       $dbxlink->exec ('LOCK TABLES Port WRITE');
+       if (alreadyUsedL2Address ($db_l2address, $object_id))
+       {
+               $dbxlink->exec ('UNLOCK TABLES');
+               return "address ${db_l2address} belongs to another object";
+       }
        $query =
                "update Port set name='$port_name', type=$port_type_id, label='$port_label', " .
                "reservation_comment = ${port_reservation_comment}, l2address=" .
                (($db_l2address === '') ? 'NULL' : "'${db_l2address}'") .
                " where id='$port_id'";
        $result = $dbxlink->exec ($query);
+       $dbxlink->exec ('UNLOCK TABLES');
        if ($result == 1)
                return '';
        $errorInfo = $dbxlink->errorInfo();
@@ -3627,4 +3643,20 @@ function getUserIDByUsername ($username)
        return NULL;
 }
 
+// Return TRUE, if the given address is assigned to a port of any object
+// except the current object. Using this function as a constraint makes
+// it possible to reuse L2 addresses within one object, yet keeping them
+// universally unique on the other hand.
+function alreadyUsedL2Address ($address, $my_object_id)
+{
+       $query = "SELECT COUNT(*) FROM Port WHERE BINARY l2address = '${address}' AND object_id != ${my_object_id}";
+       if (NULL == ($result = useSelectBlade ($query, __FUNCTION__)))
+       {
+               showError ('SQL query failed', __FUNCTION__);
+               die;
+       }
+       $row = $result->fetch (PDO::FETCH_NUM);
+       return $row[0] != 0;
+}
+
 ?>
index 2e23eb1..93bbd0a 100644 (file)
@@ -191,9 +191,9 @@ CREATE TABLE `Port` (
   `label` char(255) default NULL,
   PRIMARY KEY  (`id`),
   UNIQUE KEY `object_id` (`object_id`,`name`),
-  UNIQUE KEY `l2address` (`l2address`),
   KEY `type` (`type`),
-  KEY `comment` (`reservation_comment`)
+  KEY `comment` (`reservation_comment`),
+  KEY `l2address` (`l2address`)
 ) ENGINE=MyISAM;
 
 CREATE TABLE `PortCompat` (
index f9f082b..16b6fca 100644 (file)
@@ -239,6 +239,8 @@ CREATE TABLE `LDAPCache` (
                        $query[] = "DELETE FROM TagStorage WHERE entity_realm = 'file' AND entity_id NOT IN (SELECT id FROM File)";
                        $query[] = "INSERT INTO `Config` (varname, varvalue, vartype, emptyok, is_hidden, description) VALUES ('IPV4_ENABLE_KNIGHT','yes','string','no','no','Enable IPv4 knight feature')";
                        $query[] = "ALTER TABLE Port ADD INDEX comment (reservation_comment)";
+                       $query[] = "ALTER TABLE Port DROP KEY l2address"; // UNIQUE
+                       $query[] = "ALTER TABLE Port ADD KEY (l2address)"; // not UNIQUE
                        $query[] = "UPDATE Config SET varvalue = '0.17.2' WHERE varname = 'DB_VERSION'";
                        break;
                default: