diff options
author | Thomas Müller <thomas.mueller@tmit.eu> | 2014-10-23 13:48:33 +0200 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2014-10-23 13:48:33 +0200 |
commit | 6c1871da06d127abdf7ce2fd5d3beb7683fe42a0 (patch) | |
tree | 1c21a9a3d136ba1dc8391e12a37cdfe3ffe0bda8 /lib | |
parent | 7c14a173619cce5c3f637888865e0786a727f5c8 (diff) | |
parent | 0dcb83203910a8de5bcfaca8cbad9fef1845a2ea (diff) | |
download | nextcloud-server-6c1871da06d127abdf7ce2fd5d3beb7683fe42a0.tar.gz nextcloud-server-6c1871da06d127abdf7ce2fd5d3beb7683fe42a0.zip |
Merge pull request #10985 from owncloud/db-cleanup
Cleanup database handling
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/appframework/db/db.php | 54 | ||||
-rw-r--r-- | lib/private/db.php | 129 | ||||
-rw-r--r-- | lib/private/db/connection.php | 28 | ||||
-rw-r--r-- | lib/private/db/connectionfactory.php | 50 | ||||
-rw-r--r-- | lib/private/db/connectionwrapper.php | 99 | ||||
-rw-r--r-- | lib/private/db/mdb2schemamanager.php | 5 | ||||
-rw-r--r-- | lib/private/preferences.php | 6 | ||||
-rw-r--r-- | lib/private/server.php | 21 | ||||
-rw-r--r-- | lib/private/updater.php | 1 | ||||
-rw-r--r-- | lib/public/idbconnection.php | 72 |
10 files changed, 186 insertions, 279 deletions
diff --git a/lib/private/appframework/db/db.php b/lib/private/appframework/db/db.php index fc77a38f814..fb30505d05a 100644 --- a/lib/private/appframework/db/db.php +++ b/lib/private/appframework/db/db.php @@ -30,28 +30,42 @@ use \OCP\IDb; * Small Facade for being able to inject the database connection for tests */ class Db implements IDb { + /** + * @var \OCP\IDBConnection + */ + protected $connection; + /** + * @param \OCP\IDBConnection $connection + */ + public function __construct($connection) { + $this->connection = $connection; + } - /** - * Used to abstract the owncloud database access away - * @param string $sql the sql query with ? placeholder for params - * @param int $limit the maximum number of rows - * @param int $offset from which row we want to start - * @return \OC_DB_StatementWrapper prepared SQL query - */ - public function prepareQuery($sql, $limit=null, $offset=null){ - return \OCP\DB::prepare($sql, $limit, $offset); - } - - - /** - * Used to get the id of the just inserted element - * @param string $tableName the name of the table where we inserted the item - * @return int the id of the inserted element - */ - public function getInsertId($tableName){ - return \OCP\DB::insertid($tableName); - } + /** + * Used to abstract the owncloud database access away + * + * @param string $sql the sql query with ? placeholder for params + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return \OC_DB_StatementWrapper prepared SQL query + */ + public function prepareQuery($sql, $limit = null, $offset = null) { + $isManipulation = \OC_DB::isManipulation($sql); + $statement = $this->connection->prepare($sql, $limit, $offset); + return new \OC_DB_StatementWrapper($statement, $isManipulation); + } + + + /** + * Used to get the id of the just inserted element + * + * @param string $tableName the name of the table where we inserted the item + * @return int the id of the inserted element + */ + public function getInsertId($tableName) { + return $this->connection->lastInsertId($tableName); + } } diff --git a/lib/private/db.php b/lib/private/db.php index ba069977d35..9b904a1518f 100644 --- a/lib/private/db.php +++ b/lib/private/db.php @@ -41,87 +41,12 @@ class DatabaseException extends Exception { * Doctrine with some adaptions. */ class OC_DB { - /** - * @var \OC\DB\Connection $connection - */ - static private $connection; //the preferred connection to use, only Doctrine /** - * connects to the database - * @return boolean|null true if connection can be established or false on error - * - * Connects to the database as specified in config.php - */ - public static function connect() { - if(self::$connection) { - return true; - } - - $type = OC_Config::getValue('dbtype', 'sqlite'); - $factory = new \OC\DB\ConnectionFactory(); - if (!$factory->isValidType($type)) { - return false; - } - - $connectionParams = array( - 'user' => OC_Config::getValue('dbuser', ''), - 'password' => OC_Config::getValue('dbpassword', ''), - ); - $name = OC_Config::getValue('dbname', 'owncloud'); - - if ($factory->normalizeType($type) === 'sqlite3') { - $datadir = OC_Config::getValue("datadirectory", OC::$SERVERROOT.'/data'); - $connectionParams['path'] = $datadir.'/'.$name.'.db'; - } else { - $host = OC_Config::getValue('dbhost', ''); - if (strpos($host, ':')) { - // Host variable may carry a port or socket. - list($host, $portOrSocket) = explode(':', $host, 2); - if (ctype_digit($portOrSocket)) { - $connectionParams['port'] = $portOrSocket; - } else { - $connectionParams['unix_socket'] = $portOrSocket; - } - } - $connectionParams['host'] = $host; - $connectionParams['dbname'] = $name; - } - - $connectionParams['tablePrefix'] = OC_Config::getValue('dbtableprefix', 'oc_'); - - try { - self::$connection = $factory->getConnection($type, $connectionParams); - self::$connection->getConfiguration()->setSQLLogger(\OC::$server->getQueryLogger()); - } catch(\Doctrine\DBAL\DBALException $e) { - OC_Log::write('core', $e->getMessage(), OC_Log::FATAL); - OC_User::setUserId(null); - - // send http status 503 - header('HTTP/1.1 503 Service Temporarily Unavailable'); - header('Status: 503 Service Temporarily Unavailable'); - OC_Template::printErrorPage('Failed to connect to database'); - die(); - } - - return true; - } - - /** - * The existing database connection is closed and connected again - */ - public static function reconnect() { - if(self::$connection) { - self::$connection->close(); - self::$connection->connect(); - } - } - - /** - * @return \OC\DB\Connection + * @return \OCP\IDBConnection */ static public function getConnection() { - self::connect(); - return self::$connection; + return \OC::$server->getDatabaseConnection(); } /** @@ -131,7 +56,7 @@ class OC_DB { */ private static function getMDB2SchemaManager() { - return new \OC\DB\MDB2SchemaManager(self::getConnection()); + return new \OC\DB\MDB2SchemaManager(\OC::$server->getDatabaseConnection()); } /** @@ -146,7 +71,7 @@ class OC_DB { * SQL query via Doctrine prepare(), needs to be execute()'d! */ static public function prepare( $query , $limit = null, $offset = null, $isManipulation = null) { - self::connect(); + $connection = \OC::$server->getDatabaseConnection(); if ($isManipulation === null) { //try to guess, so we return the number of rows on manipulations @@ -155,7 +80,7 @@ class OC_DB { // return the result try { - $result = self::$connection->prepare($query, $limit, $offset); + $result =$connection->prepare($query, $limit, $offset); } catch (\Doctrine\DBAL\DBALException $e) { throw new \DatabaseException($e->getMessage(), $query); } @@ -252,8 +177,7 @@ class OC_DB { * cause trouble! */ public static function insertid($table=null) { - self::connect(); - return self::$connection->lastInsertId($table); + return \OC::$server->getDatabaseConnection()->lastInsertId($table); } /** @@ -263,24 +187,21 @@ class OC_DB { * @return boolean number of updated rows */ public static function insertIfNotExist($table, $input) { - self::connect(); - return self::$connection->insertIfNotExist($table, $input); + return \OC::$server->getDatabaseConnection()->insertIfNotExist($table, $input); } /** * Start a transaction */ public static function beginTransaction() { - self::connect(); - self::$connection->beginTransaction(); + return \OC::$server->getDatabaseConnection()->beginTransaction(); } /** * Commit the database changes done during a transaction that is in progress */ public static function commit() { - self::connect(); - self::$connection->commit(); + return \OC::$server->getDatabaseConnection()->commit(); } /** @@ -348,17 +269,17 @@ class OC_DB { * @param string $tableName the table to drop */ public static function dropTable($tableName) { - + $connection = \OC::$server->getDatabaseConnection(); $tableName = OC_Config::getValue('dbtableprefix', 'oc_' ) . trim($tableName); - self::$connection->beginTransaction(); + $connection->beginTransaction(); - $platform = self::$connection->getDatabasePlatform(); + $platform = $connection->getDatabasePlatform(); $sql = $platform->getDropTableSQL($platform->quoteIdentifier($tableName)); - self::$connection->query($sql); + $connection->executeQuery($sql); - self::$connection->commit(); + $connection->commit(); } /** @@ -398,8 +319,8 @@ class OC_DB { } public static function getErrorCode($error) { - $code = self::$connection->errorCode(); - return $code; + $connection = \OC::$server->getDatabaseConnection(); + return $connection->errorCode(); } /** * returns the error code and message as a string for logging @@ -408,22 +329,8 @@ class OC_DB { * @return string */ public static function getErrorMessage($error) { - if (self::$connection) { - return self::$connection->getError(); - } - return ''; - } - - /** - * @param bool $enabled - */ - static public function enableCaching($enabled) { - self::connect(); - if ($enabled) { - self::$connection->enableQueryStatementCaching(); - } else { - self::$connection->disableQueryStatementCaching(); - } + $connection = \OC::$server->getDatabaseConnection(); + return $connection->getError(); } /** diff --git a/lib/private/db/connection.php b/lib/private/db/connection.php index b7981fcd691..a6cdf858899 100644 --- a/lib/private/db/connection.php +++ b/lib/private/db/connection.php @@ -11,8 +11,9 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Configuration; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\Common\EventManager; +use OCP\IDBConnection; -class Connection extends \Doctrine\DBAL\Connection { +class Connection extends \Doctrine\DBAL\Connection implements IDBConnection { /** * @var string $tablePrefix */ @@ -24,13 +25,6 @@ class Connection extends \Doctrine\DBAL\Connection { protected $adapter; /** - * @var \Doctrine\DBAL\Driver\Statement[] $preparedQueries - */ - protected $preparedQueries = array(); - - protected $cachingQueryStatementEnabled = true; - - /** * Initializes a new instance of the Connection class. * * @param array $params The connection parameters. @@ -69,9 +63,6 @@ class Connection extends \Doctrine\DBAL\Connection { $platform = $this->getDatabasePlatform(); $statement = $platform->modifyLimitQuery($statement, $limit, $offset); } else { - if (isset($this->preparedQueries[$statement]) && $this->cachingQueryStatementEnabled) { - return $this->preparedQueries[$statement]; - } $origStatement = $statement; } $statement = $this->replaceTablePrefix($statement); @@ -80,11 +71,7 @@ class Connection extends \Doctrine\DBAL\Connection { if(\OC_Config::getValue( 'log_query', false)) { \OC_Log::write('core', 'DB prepare : '.$statement, \OC_Log::DEBUG); } - $result = parent::prepare($statement); - if (is_null($limit) && $this->cachingQueryStatementEnabled) { - $this->preparedQueries[$origStatement] = $result; - } - return $result; + return parent::prepare($statement); } /** @@ -185,13 +172,4 @@ class Connection extends \Doctrine\DBAL\Connection { protected function replaceTablePrefix($statement) { return str_replace( '*PREFIX*', $this->tablePrefix, $statement ); } - - public function enableQueryStatementCaching() { - $this->cachingQueryStatementEnabled = true; - } - - public function disableQueryStatementCaching() { - $this->cachingQueryStatementEnabled = false; - $this->preparedQueries = array(); - } } diff --git a/lib/private/db/connectionfactory.php b/lib/private/db/connectionfactory.php index 589a1c0affd..1f676f1fca2 100644 --- a/lib/private/db/connectionfactory.php +++ b/lib/private/db/connectionfactory.php @@ -98,19 +98,6 @@ class ConnectionFactory { new \Doctrine\DBAL\Configuration(), $eventManager ); - switch ($normalizedType) { - case 'sqlite3': - // Sqlite doesn't handle query caching and schema changes - // TODO: find a better way to handle this - /** @var $connection \OC\DB\Connection */ - $connection->disableQueryStatementCaching(); - break; - case 'oci': - // oracle seems to have issues with cached statements which have been closed - /** @var $connection \OC\DB\Connection */ - $connection->disableQueryStatementCaching(); - break; - } return $connection; } @@ -131,4 +118,41 @@ class ConnectionFactory { $normalizedType = $this->normalizeType($type); return isset($this->defaultConnectionParams[$normalizedType]); } + + /** + * Create the connection parameters for the config + * + * @param \OCP\IConfig $config + * @return array + */ + public function createConnectionParams($config) { + $type = $config->getSystemValue('dbtype', 'sqlite'); + + $connectionParams = array( + 'user' => $config->getSystemValue('dbuser', ''), + 'password' => $config->getSystemValue('dbpassword', ''), + ); + $name = $config->getSystemValue('dbname', 'owncloud'); + + if ($this->normalizeType($type) === 'sqlite3') { + $datadir = $config->getSystemValue("datadirectory", \OC::$SERVERROOT . '/data'); + $connectionParams['path'] = $datadir . '/' . $name . '.db'; + } else { + $host = $config->getSystemValue('dbhost', ''); + if (strpos($host, ':')) { + // Host variable may carry a port or socket. + list($host, $portOrSocket) = explode(':', $host, 2); + if (ctype_digit($portOrSocket)) { + $connectionParams['port'] = $portOrSocket; + } else { + $connectionParams['unix_socket'] = $portOrSocket; + } + } + $connectionParams['host'] = $host; + $connectionParams['dbname'] = $name; + } + + $connectionParams['tablePrefix'] = $config->getSystemValue('dbtableprefix', 'oc_'); + return $connectionParams; + } } diff --git a/lib/private/db/connectionwrapper.php b/lib/private/db/connectionwrapper.php deleted file mode 100644 index 132e76666ab..00000000000 --- a/lib/private/db/connectionwrapper.php +++ /dev/null @@ -1,99 +0,0 @@ -<?php -/** - * Copyright (c) 2013 Thomas Müller <deepdiver@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 ConnectionWrapper implements \OCP\IDBConnection { - - private $connection; - - public function __construct(Connection $conn) { - $this->connection = $conn; - } - - /** - * Used to the owncloud database access away - * @param string $sql the sql query with ? placeholder for params - * @param int $limit the maximum number of rows - * @param int $offset from which row we want to start - * @return \Doctrine\DBAL\Driver\Statement The prepared statement. - */ - public function prepare($sql, $limit = null, $offset = null) - { - return $this->connection->prepare($sql, $limit, $offset); - } - - /** - * Used to get the id of the just inserted element - * @param string $table the name of the table where we inserted the item - * @return string the id of the inserted element - */ - public function lastInsertId($table = null) - { - return $this->connection->lastInsertId($table); - } - - /** - * Insert a row if a matching row doesn't exists. - * @param string $table The table name (will replace *PREFIX*) to perform the replace on. - * @param array $input - * - * The input array if in the form: - * - * array ( 'id' => array ( 'value' => 6, - * 'key' => true - * ), - * 'name' => array ('value' => 'Stoyan'), - * 'family' => array ('value' => 'Stefanov'), - * 'birth_date' => array ('value' => '1975-06-20') - * ); - * @return bool - * - */ - public function insertIfNotExist($table, $input) - { - return $this->connection->insertIfNotExist($table, $input); - } - - /** - * Start a transaction - * @return bool TRUE on success or FALSE on failure - */ - public function beginTransaction() - { - return $this->connection->beginTransaction(); - } - - /** - * Commit the database changes done during a transaction that is in progress - * @return bool TRUE on success or FALSE on failure - */ - public function commit() - { - return $this->connection->commit(); - } - - /** - * Rollback the database changes done during a transaction that is in progress - * @return bool TRUE on success or FALSE on failure - */ - public function rollBack() - { - return $this->connection->rollBack(); - } - - /** - * Gets the error code and message as a string for logging - * @return string - */ - public function getError() - { - return $this->connection->getError(); - } -} diff --git a/lib/private/db/mdb2schemamanager.php b/lib/private/db/mdb2schemamanager.php index ea1e512002d..3c367f144db 100644 --- a/lib/private/db/mdb2schemamanager.php +++ b/lib/private/db/mdb2schemamanager.php @@ -21,7 +21,7 @@ class MDB2SchemaManager { protected $conn; /** - * @param \OC\DB\Connection $conn + * @param \OCP\IDBConnection $conn */ public function __construct($conn) { $this->conn = $conn; @@ -155,7 +155,8 @@ class MDB2SchemaManager { $this->conn->commit(); if ($this->conn->getDatabasePlatform() instanceof SqlitePlatform) { - \OC_DB::reconnect(); + $this->conn->close(); + $this->conn->connect(); } return true; } diff --git a/lib/private/preferences.php b/lib/private/preferences.php index a849cc23e1a..cdaa207449d 100644 --- a/lib/private/preferences.php +++ b/lib/private/preferences.php @@ -36,7 +36,7 @@ namespace OC; -use \OC\DB\Connection; +use OCP\IDBConnection; /** @@ -61,9 +61,9 @@ class Preferences { protected $cache = array(); /** - * @param \OC\DB\Connection $conn + * @param \OCP\IDBConnection $conn */ - public function __construct(Connection $conn) { + public function __construct(IDBConnection $conn) { $this->conn = $conn; } diff --git a/lib/private/server.php b/lib/private/server.php index f7ffee484ea..b0d63af1554 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -217,8 +217,25 @@ class Server extends SimpleContainer implements IServerContainer { $this->registerService('Crypto', function ($c) { return new Crypto(\OC::$server->getConfig(), \OC::$server->getSecureRandom()); }); + $this->registerService('DatabaseConnection', function ($c) { + /** + * @var Server $c + */ + $factory = new \OC\DB\ConnectionFactory(); + $type = $c->getConfig()->getSystemValue('dbtype', 'sqlite'); + if (!$factory->isValidType($type)) { + throw new \DatabaseException('Invalid database type'); + } + $connectionParams = $factory->createConnectionParams($c->getConfig()); + $connection = $factory->getConnection($type, $connectionParams); + $connection->getConfiguration()->setSQLLogger($c->getQueryLogger()); + return $connection; + }); $this->registerService('Db', function ($c) { - return new Db(); + /** + * @var Server $c + */ + return new Db($c->getDatabaseConnection()); }); $this->registerService('HTTPHelper', function (SimpleContainer $c) { $config = $c->query('AllConfig'); @@ -469,7 +486,7 @@ class Server extends SimpleContainer implements IServerContainer { * @return \OCP\IDBConnection */ function getDatabaseConnection() { - return new ConnectionWrapper(\OC_DB::getConnection()); + return $this->query('DatabaseConnection'); } /** diff --git a/lib/private/updater.php b/lib/private/updater.php index 38a281cd2f8..c4c70a3cc4a 100644 --- a/lib/private/updater.php +++ b/lib/private/updater.php @@ -129,7 +129,6 @@ class Updater extends BasicEmitter { * @return bool true if the operation succeeded, false otherwise */ public function upgrade() { - \OC_DB::enableCaching(false); \OC_Config::setValue('maintenance', true); $installedVersion = \OC_Config::getValue('version', '0.0.0'); diff --git a/lib/public/idbconnection.php b/lib/public/idbconnection.php index 3e6624e07e9..ce17d293e86 100644 --- a/lib/public/idbconnection.php +++ b/lib/public/idbconnection.php @@ -44,6 +44,32 @@ interface IDBConnection { public function prepare($sql, $limit=null, $offset=null); /** + * Executes an, optionally parameterized, SQL query. + * + * If the query is parameterized, a prepared statement is used. + * If an SQLLogger is configured, the execution is logged. + * + * @param string $query The SQL query to execute. + * @param string[] $params The parameters to bind to the query, if any. + * @param array $types The types the previous parameters are in. + * @return \Doctrine\DBAL\Driver\Statement The executed statement. + */ + public function executeQuery($query, array $params = array(), $types = array()); + + /** + * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters + * and returns the number of affected rows. + * + * This method supports PDO binding types as well as DBAL mapping types. + * + * @param string $query The SQL query. + * @param array $params The query parameters. + * @param array $types The parameter types. + * @return integer The number of affected rows. + */ + public function executeUpdate($query, array $params = array(), array $types = array()); + + /** * Used to get the id of the just inserted element * @param string $table the name of the table where we inserted the item * @return int the id of the inserted element @@ -71,19 +97,16 @@ interface IDBConnection { /** * Start a transaction - * @return bool TRUE on success or FALSE on failure */ public function beginTransaction(); /** * Commit the database changes done during a transaction that is in progress - * @return bool TRUE on success or FALSE on failure */ public function commit(); /** * Rollback the database changes done during a transaction that is in progress - * @return bool TRUE on success or FALSE on failure */ public function rollBack(); @@ -92,4 +115,47 @@ interface IDBConnection { * @return string */ public function getError(); + + /** + * Fetch the SQLSTATE associated with the last database operation. + * + * @return integer The last error code. + */ + public function errorCode(); + + /** + * Fetch extended error information associated with the last database operation. + * + * @return array The last error information. + */ + public function errorInfo(); + + /** + * Establishes the connection with the database. + * + * @return bool + */ + public function connect(); + + /** + * Close the database connection + */ + public function close(); + + /** + * Quotes a given input parameter. + * + * @param mixed $input Parameter to be quoted. + * @param int $type Type of the parameter. + * @return string The quoted parameter. + */ + public function quote($input, $type = \PDO::PARAM_STR); + + /** + * Gets the DatabasePlatform instance that provides all the metadata about + * the platform this driver connects to. + * + * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform. + */ + public function getDatabasePlatform(); } |