[Pkg-owncloud-commits] [owncloud] 96/118: SQLite autoincrement fix backport

David Prévot taffit at moszumanska.debian.org
Fri Mar 27 22:13:18 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch stable8
in repository owncloud.

commit b896be821fce0b998d5b11f5a8a99430b42ca357
Author: Vincent Petry <pvince81 at owncloud.com>
Date:   Tue Mar 3 11:14:45 2015 +0100

    SQLite autoincrement fix backport
    
    Add custom sqlite platform to set auto increment
    
    Add repair step to fix SQLite autoincrement
    
    Force Doctrine to generate alter table SQL statements for SQLite to make
    sure the code from OCSqlitePlatform is triggered.
---
 lib/private/db/connectionfactory.php           |  1 +
 lib/private/db/ocsqliteplatform.php            | 35 +++++++++++
 lib/private/repair.php                         |  2 +
 lib/repair/sqliteautoincrement.php             | 85 ++++++++++++++++++++++++++
 tests/lib/files/cache/cache.php                | 13 ++++
 tests/lib/repair/repairsqliteautoincrement.php | 81 ++++++++++++++++++++++++
 version.php                                    |  2 +-
 7 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php
index 44b598d..b86e731 100644
--- a/lib/private/db/connectionfactory.php
+++ b/lib/private/db/connectionfactory.php
@@ -96,6 +96,7 @@ class ConnectionFactory {
 				break;
 			case 'sqlite3':
 				$journalMode = $additionalConnectionParams['sqlite.journal_mode'];
+				$additionalConnectionParams['platform'] = new OCSqlitePlatform();
 				$eventManager->addEventSubscriber(new SQLiteSessionInit(true, $journalMode));
 				break;
 		}
diff --git a/lib/private/db/ocsqliteplatform.php b/lib/private/db/ocsqliteplatform.php
new file mode 100644
index 0000000..fe39e20
--- /dev/null
+++ b/lib/private/db/ocsqliteplatform.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Copyright (c) 2015 Robin Appelman <icewind at owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\DB;
+
+class OCSqlitePlatform extends \Doctrine\DBAL\Platforms\SqlitePlatform {
+	/**
+	 * {@inheritDoc}
+	 */
+	public function getColumnDeclarationSQL($name, array $field) {
+		$def = parent::getColumnDeclarationSQL($name, $field);
+		if (!empty($field['autoincrement'])) {
+			$def .= ' PRIMARY KEY AUTOINCREMENT';
+		}
+		return $def;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	protected function _getCreateTableSQL($name, array $columns, array $options = array()){
+		// if auto increment is set the column is already defined as primary key
+		foreach ($columns as $column) {
+			if (!empty($column['autoincrement'])) {
+				$options['primary'] = null;
+			}
+		}
+		return parent::_getCreateTableSQL($name, $columns, $options);
+	}
+}
diff --git a/lib/private/repair.php b/lib/private/repair.php
index c742838..c71af98 100644
--- a/lib/private/repair.php
+++ b/lib/private/repair.php
@@ -13,6 +13,7 @@ use OC\Hooks\Emitter;
 use OC\Repair\AssetCache;
 use OC\Repair\CleanTags;
 use OC\Repair\Collation;
+use OC\Repair\SqliteAutoincrement;
 use OC\Repair\EnableFilesApp;
 use OC\Repair\FillETags;
 use OC\Repair\InnoDB;
@@ -99,6 +100,7 @@ class Repair extends BasicEmitter {
 		$steps = array(
 			new InnoDB(),
 			new Collation(\OC::$server->getConfig(), \OC_DB::getConnection()),
+			new SqliteAutoincrement(\OC_DB::getConnection()),
 			new SearchLuceneTables(),
 			new RepairConfig()
 		);
diff --git a/lib/repair/sqliteautoincrement.php b/lib/repair/sqliteautoincrement.php
new file mode 100644
index 0000000..79b1fe7
--- /dev/null
+++ b/lib/repair/sqliteautoincrement.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81 at owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Repair;
+
+use Doctrine\DBAL\Platforms\SqlitePlatform;
+use Doctrine\DBAL\Schema\SchemaException;
+use Doctrine\DBAL\Schema\SchemaDiff;
+use Doctrine\DBAL\Schema\TableDiff;
+use Doctrine\DBAL\Schema\ColumnDiff;
+use OC\Hooks\BasicEmitter;
+
+/**
+ * Fixes Sqlite autoincrement by forcing the SQLite table schemas to be
+ * altered in order to retrigger SQL schema generation through OCSqlitePlatform.
+ */
+class SqliteAutoincrement extends BasicEmitter implements \OC\RepairStep {
+	/**
+	 * @var \OC\DB\Connection
+	 */
+	protected $connection;
+
+	/**
+	 * @param \OC\DB\Connection $connection
+	 */
+	public function __construct($connection) {
+		$this->connection = $connection;
+	}
+
+	public function getName() {
+		return 'Repair SQLite autoincrement';
+	}
+
+	/**
+	 * Fix mime types
+	 */
+	public function run() {
+		if (!$this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
+			return;
+		}
+
+		$sourceSchema = $this->connection->getSchemaManager()->createSchema();
+
+		$schemaDiff = new SchemaDiff();
+
+		foreach ($sourceSchema->getTables() as $tableSchema) {
+			$primaryKey = $tableSchema->getPrimaryKey();
+			if (!$primaryKey) {
+				continue;
+			}
+
+			$columnNames = $primaryKey->getColumns();
+
+			// add a column diff for every primary key column,
+			// but do not actually change anything, this will
+			// force the generation of SQL statements to alter
+			// those tables, which will then trigger the
+			// specific SQL code from OCSqlitePlatform
+			try {
+				$tableDiff = new TableDiff($tableSchema->getName());
+				$tableDiff->fromTable = $tableSchema;
+				foreach ($columnNames as $columnName) {
+					$columnSchema = $tableSchema->getColumn($columnName);
+					$columnDiff = new ColumnDiff($columnSchema->getName(), $columnSchema);
+					$tableDiff->changedColumns[] = $columnDiff;
+					$schemaDiff->changedTables[] = $tableDiff;
+				}
+			} catch (SchemaException $e) {
+				// ignore
+			}
+		}
+
+		$this->connection->beginTransaction();
+		foreach ($schemaDiff->toSql($this->connection->getDatabasePlatform()) as $sql) {
+			$this->connection->query($sql);
+		}
+		$this->connection->commit();
+	}
+}
+
diff --git a/tests/lib/files/cache/cache.php b/tests/lib/files/cache/cache.php
index 15bcff2..3f86963 100644
--- a/tests/lib/files/cache/cache.php
+++ b/tests/lib/files/cache/cache.php
@@ -572,6 +572,19 @@ class Cache extends \Test\TestCase {
 		$this->assertEquals($newData, $newDataFromBogus);
 	}
 
+	public function testNoReuseOfFileId() {
+		$data1 = array('size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain');
+		$this->cache->put('somefile.txt', $data1);
+		$info = $this->cache->get('somefile.txt');
+		$fileId = $info['fileid'];
+		$this->cache->remove('somefile.txt');
+		$data2 = array('size' => 200, 'mtime' => 100, 'mimetype' => 'text/plain');
+		$this->cache->put('anotherfile.txt', $data2);
+		$info2 = $this->cache->get('anotherfile.txt');
+		$fileId2 = $info2['fileid'];
+		$this->assertNotEquals($fileId, $fileId2);
+	}
+
 	protected function tearDown() {
 		if ($this->cache) {
 			$this->cache->clear();
diff --git a/tests/lib/repair/repairsqliteautoincrement.php b/tests/lib/repair/repairsqliteautoincrement.php
new file mode 100644
index 0000000..f81e08b
--- /dev/null
+++ b/tests/lib/repair/repairsqliteautoincrement.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright (c) 2015 Vincent Petry <pvince81 at owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Repair;
+
+/**
+ * Tests for fixing the SQLite id recycling
+ */
+class TestRepairSqliteAutoincrement extends \Test\TestCase {
+
+	/**
+	 * @var \OC\Repair\SqliteAutoincrement
+	 */
+	private $repair;
+
+	/**
+	 * @var \Doctrine\DBAL\Connection
+	 */
+	private $connection;
+
+	/**
+	 * @var string
+	 */
+	private $tableName;
+
+	/**
+	 * @var \OCP\IConfig
+	 */
+	private $config;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$this->connection = \OC_DB::getConnection();
+		$this->config = \OC::$server->getConfig();
+		if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
+			$this->markTestSkipped("Test only relevant on Sqlite");
+		}
+
+		$dbPrefix = $this->config->getSystemValue('dbtableprefix', 'oc_');
+		$this->tableName = $this->getUniqueID($dbPrefix . 'autoinc_test');
+		$this->connection->exec('CREATE TABLE ' . $this->tableName . '("someid" INTEGER NOT NULL, "text" VARCHAR(16), PRIMARY KEY("someid"))');
+
+		$this->repair = new \OC\Repair\SqliteAutoincrement($this->connection);
+	}
+
+	protected function tearDown() {
+		$this->connection->getSchemaManager()->dropTable($this->tableName);
+		parent::tearDown();
+	}
+
+	/**
+	 * Tests whether autoincrement works
+	 *
+	 * @return boolean true if autoincrement works, false otherwise
+	 */
+	protected function checkAutoincrement() {
+		$this->connection->executeUpdate('INSERT INTO ' . $this->tableName . ' ("text") VALUES ("test")');
+		$insertId = $this->connection->lastInsertId();
+		$this->connection->executeUpdate('DELETE FROM ' . $this->tableName . ' WHERE "someid" = ?', array($insertId));
+
+		// insert again
+		$this->connection->executeUpdate('INSERT INTO ' . $this->tableName . ' ("text") VALUES ("test2")');
+		$newInsertId = $this->connection->lastInsertId();
+
+		return ($insertId !== $newInsertId);
+	}
+
+	public function testConvertIdColumn() {
+		$this->assertFalse($this->checkAutoincrement());
+
+		$this->repair->run();
+
+		$this->assertTrue($this->checkAutoincrement());
+	}
+}
diff --git a/version.php b/version.php
index fb8b1ee..8c4a476 100644
--- a/version.php
+++ b/version.php
@@ -3,7 +3,7 @@
 // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
 // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
 // when updating major/minor version number.
-$OC_Version=array(8, 0, 2, 0);
+$OC_Version=array(8, 0, 2, 1);
 
 // The human readable string
 $OC_VersionString='8.0.2';

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list