aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_framework
diff options
context:
space:
mode:
authorPatrick Webster <noxwizard@phpbb.com>2012-11-18 20:38:58 -0600
committerPatrick Webster <noxwizard@phpbb.com>2012-11-18 20:38:58 -0600
commit41a95d2c646aba8d6a66ee046c532a51a9022784 (patch)
tree2f087bea13af7fd9cd5c0be1b4d6b2619996844f /tests/test_framework
parentaf5d8b502ebf454e058794b8b082f62b4fa4cbe5 (diff)
downloadforums-41a95d2c646aba8d6a66ee046c532a51a9022784.tar
forums-41a95d2c646aba8d6a66ee046c532a51a9022784.tar.gz
forums-41a95d2c646aba8d6a66ee046c532a51a9022784.tar.bz2
forums-41a95d2c646aba8d6a66ee046c532a51a9022784.tar.xz
forums-41a95d2c646aba8d6a66ee046c532a51a9022784.zip
[ticket/11219] Update sequence values after loading fixtures
If a value is provide for an auto_increment type of column, certain DBMSes do not update their internal sequencers. If a row is inserted later, it can be given an ID that is already in use, resulting in an error. The database test cases now resynchronise the sequencers before the tests are run. PHPBB3-11219
Diffstat (limited to 'tests/test_framework')
-rw-r--r--tests/test_framework/phpbb_database_test_case.php10
-rw-r--r--tests/test_framework/phpbb_database_test_connection_manager.php129
2 files changed, 139 insertions, 0 deletions
diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php
index 75a3c0944b..0916679108 100644
--- a/tests/test_framework/phpbb_database_test_case.php
+++ b/tests/test_framework/phpbb_database_test_case.php
@@ -28,6 +28,16 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
);
}
+ protected function setUp()
+ {
+ parent::setUp();
+
+ $config = $this->get_database_config();
+ $manager = $this->create_connection_manager($config);
+ $manager->connect();
+ $manager->post_setup_synchronisation();
+ }
+
public function createXMLDataSet($path)
{
$db_config = $this->get_database_config();
diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php
index a43215bcf2..cae1720587 100644
--- a/tests/test_framework/phpbb_database_test_connection_manager.php
+++ b/tests/test_framework/phpbb_database_test_connection_manager.php
@@ -426,4 +426,133 @@ class phpbb_database_test_connection_manager
$this->pdo->exec($query);
}
}
+
+ /**
+ * Performs synchronisations on the database after a fixture has been loaded
+ */
+ public function post_setup_synchronisation()
+ {
+ $this->ensure_connected(__METHOD__);
+ $queries = array();
+
+ switch ($this->config['dbms'])
+ {
+ case 'oracle':
+ // Get all of the information about the sequences
+ $sql = "SELECT t.table_name, tc.column_name, d.referenced_name as sequence_name
+ FROM USER_TRIGGERS t
+ JOIN USER_DEPENDENCIES d on d.name = t.trigger_name
+ JOIN USER_TRIGGER_COLS tc on (tc.trigger_name = t.trigger_name)
+ WHERE d.referenced_type = 'SEQUENCE'
+ AND d.type = 'TRIGGER'";
+ $result = $this->pdo->query($sql);
+
+ while ($row = $result->fetch(PDO::FETCH_ASSOC))
+ {
+ // Get the current max value of the table
+ $sql = "SELECT MAX({$row['COLUMN_NAME']}) + 1 FROM {$row['TABLE_NAME']}";
+
+ $max_result = $this->pdo->query($sql);
+ $max_row = $max_result->fetch(PDO::FETCH_NUM);
+
+ if (!$max_row)
+ {
+ continue;
+ }
+
+ $maxval = current($max_row);
+ if ($maxval == null)
+ {
+ $maxval = 1;
+ }
+
+ // Get the sequence's next value
+ $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual";
+ try
+ {
+ $nextval_result = $this->pdo->query($sql);
+ }
+ catch (PDOException $e)
+ {
+ // If we catch an exception here it's because the sequencer hasn't been initialized yet.
+ // If the table hasn't been used, then there's nothing to do.
+ continue;
+ }
+ $nextval_row = $nextval_result->fetch(PDO::FETCH_NUM);
+
+ if ($nextval_row)
+ {
+ $nextval = current($nextval_row);
+
+ // Make sure we aren't setting the new increment to zero.
+ if ($maxval != $nextval)
+ {
+ // This is a multi-step process. First we need to get the sequence back into position.
+ // That means either advancing it or moving it backwards. Sequences have a minimum value
+ // of 1, so you cannot go past that. Once the offset it determined, you have to request
+ // the next sequence value to actually move the pointer into position. So if you're at 21
+ // and need to be back at 1, set the incrementer to -20. When it's requested, it'll give
+ // you 1. Then we have to set the increment amount back to 1 to resume normal behavior.
+
+ // Move the sequence to the correct position.
+ $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY " . ($maxval - $nextval);
+ $this->pdo->exec($sql);
+
+ // Select the next value to actually update the sequence values
+ $sql = "SELECT {$row['SEQUENCE_NAME']}.nextval FROM dual";
+ $this->pdo->query($sql);
+
+ // Reset the sequence's increment amount
+ $sql = "ALTER SEQUENCE {$row['SEQUENCE_NAME']} INCREMENT BY 1";
+ $this->pdo->exec($sql);
+ }
+ }
+ }
+ break;
+
+ case 'postgres':
+ // First get the sequences
+ $sequences = array();
+ $sql = "SELECT relname FROM pg_class WHERE relkind = 'S'";
+ $result = $this->pdo->query($sql);
+ while ($row = $result->fetch(PDO::FETCH_ASSOC))
+ {
+ $sequences[] = $row['relname'];
+ }
+
+ // Now get the name of the column using it
+ foreach ($sequences as $sequence)
+ {
+ $table = str_replace('_seq', '', $sequence);
+ $sql = "SELECT column_name FROM information_schema.columns
+ WHERE table_name = '$table'
+ AND column_default = 'nextval(''$sequence''::regclass)'";
+ $result = $this->pdo->query($sql);
+ $row = $result->fetch(PDO::FETCH_ASSOC);
+
+ // Finally, set the new sequence value
+ if ($row)
+ {
+ $column = $row['column_name'];
+
+ // Get the old value if it exists, or use 1 if it doesn't
+ $sql = "SELECT COALESCE((SELECT MAX({$column}) + 1 FROM {$table}), 1) AS val";
+ $result = $this->pdo->query($sql);
+ $row = $result->fetch(PDO::FETCH_ASSOC);
+
+ if ($row)
+ {
+ // The last parameter is false so that the system doesn't increment it again
+ $queries[] = "SELECT SETVAL('{$sequence}', {$row['val']}, false)";
+ }
+ }
+ }
+ break;
+ }
+
+ foreach ($queries as $query)
+ {
+ $this->pdo->exec($query);
+ }
+ }
}