From: Bart Visscher Date: Sat, 23 Feb 2013 11:12:51 +0000 (+0100) Subject: Merge branch 'master' into doctrine X-Git-Tag: v6.0.0alpha2~444^2~46 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c8ec1bd2a64e0df6337080e6687fc5735a569313;p=nextcloud-server.git Merge branch 'master' into doctrine Conflicts: lib/base.php lib/db.php --- c8ec1bd2a64e0df6337080e6687fc5735a569313 diff --cc lib/base.php index 7acad72f02a,b5439c00abf..8a665603bb5 --- a/lib/base.php +++ b/lib/base.php @@@ -77,43 -78,41 +78,45 @@@ class OC * SPL autoload */ public static function autoload($className) { - if(array_key_exists($className, OC::$CLASSPATH)) { + if (array_key_exists($className, OC::$CLASSPATH)) { $path = OC::$CLASSPATH[$className]; /** @TODO: Remove this when necessary - Remove "apps/" from inclusion path for smooth migration to mutli app dir - */ - if (strpos($path, 'apps/')===0) { - OC_Log::write('core', 'include path for class "'.$className.'" starts with "apps/"', OC_Log::DEBUG); + Remove "apps/" from inclusion path for smooth migration to mutli app dir + */ + if (strpos($path, 'apps/') === 0) { + OC_Log::write('core', 'include path for class "' . $className . '" starts with "apps/"', OC_Log::DEBUG); $path = str_replace('apps/', '', $path); } - } - elseif(strpos($className, 'OC_')===0) { + } elseif (strpos($className, 'OC_') === 0) { $path = strtolower(str_replace('_', '/', substr($className, 3)) . '.php'); - } - elseif(strpos($className, 'OCP\\')===0) { - $path = 'public/'.strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - } - elseif(strpos($className, 'OCA\\')===0) { - $path = 'apps/'.strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); - } - elseif(strpos($className, 'Sabre_')===0) { - $path = str_replace('_', '/', $className) . '.php'; - } - elseif(strpos($className, 'Doctrine\\Common')===0) { + } elseif (strpos($className, 'OC\\') === 0) { + $path = strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + } elseif (strpos($className, 'OCP\\') === 0) { + $path = 'public/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + } elseif (strpos($className, 'OCA\\') === 0) { + foreach (self::$APPSROOTS as $appDir) { + $path = $appDir['path'] . '/' . strtolower(str_replace('\\', '/', substr($className, 3)) . '.php'); + $fullPath = stream_resolve_include_path($path); + if (file_exists($fullPath)) { + require_once $fullPath; + return false; + } + } + } elseif (strpos($className, 'Sabre_') === 0) { + $path = str_replace('_', '/', $className) . '.php'; ++ } elseif(strpos($className, 'Doctrine\\Common')===0) { + $path = 'doctrine/common/lib/'.str_replace('\\', '/', $className) . '.php'; - } - elseif(strpos($className, 'Doctrine\\DBAL')===0) { ++ } elseif(strpos($className, 'Doctrine\\DBAL')===0) { + $path = 'doctrine/dbal/lib/'.str_replace('\\', '/', $className) . '.php'; - } - elseif(strpos($className, 'Symfony\\Component\\Routing\\')===0) { - $path = 'symfony/routing/'.str_replace('\\', '/', $className) . '.php'; - } - elseif(strpos($className, 'Sabre\\VObject')===0) { + } elseif (strpos($className, 'Symfony\\Component\\Routing\\') === 0) { + $path = 'symfony/routing/' . str_replace('\\', '/', $className) . '.php'; + } elseif (strpos($className, 'Sabre\\VObject') === 0) { $path = str_replace('\\', '/', $className) . '.php'; - } - elseif(strpos($className, 'Test_')===0) { - $path = 'tests/lib/'.strtolower(str_replace('_', '/', substr($className, 5)) . '.php'); - }else{ + } elseif (strpos($className, 'Test_') === 0) { + $path = 'tests/lib/' . strtolower(str_replace('_', '/', substr($className, 5)) . '.php'); + } elseif (strpos($className, 'Test\\') === 0) { + $path = 'tests/lib/' . strtolower(str_replace('\\', '/', substr($className, 5)) . '.php'); + } else { return false; } diff --cc lib/db.php index 2e21a11d545,edbc2fe13ed..e10a5484662 --- a/lib/db.php +++ b/lib/db.php @@@ -20,24 -20,46 +20,40 @@@ * */ +define('MDB2_SCHEMA_DUMP_STRUCTURE', '1'); ++ + class DatabaseException extends Exception{ + private $query; + + public function __construct($message, $query){ + parent::__construct($message); + $this->query = $query; + } + + public function getQuery(){ + return $this->query; + } + } + /** * This class manages the access to the database. It basically is a wrapper for - * MDB2 with some adaptions. + * Doctrine with some adaptions. */ class OC_DB { - const BACKEND_PDO=0; - const BACKEND_MDB2=1; + const BACKEND_DOCTRINE=2; + static private $preparedQueries = array(); + /** - * @var MDB2_Driver_Common + * @var \Doctrine\DBAL\Connection */ - static private $connection; //the prefered connection to use, either PDO or MDB2 + static private $connection; //the prefered connection to use, only Doctrine static private $backend=null; /** - * @var MDB2_Driver_Common - */ - static private $MDB2=null; - /** - * @var PDO - */ - static private $PDO=null; - /** - * @var MDB2_Schema + * @var Doctrine */ - static private $schema=null; + static private $DOCTRINE=null; + static private $inTransaction=false; static private $prefix=null; static private $type=null; @@@ -146,8 -281,28 +163,19 @@@ default: return false; } - self::$DOCTRINE = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config); - - // Try to establish connection - self::$MDB2 = MDB2::factory( $dsn, $options ); - - // Die if we could not connect - if( PEAR::isError( self::$MDB2 )) { - OC_Log::write('core', self::$MDB2->getUserInfo(), OC_Log::FATAL); - OC_Log::write('core', self::$MDB2->getMessage(), OC_Log::FATAL); ++ try { ++ self::$DOCTRINE = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config); ++ } 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(); + } - - // We always, really always want associative arrays - self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC); } - - // we are done. great! return true; } @@@ -163,23 -318,33 +191,28 @@@ static public function prepare( $query , $limit=null, $offset=null ) { if (!is_null($limit) && $limit != -1) { - if (self::$backend == self::BACKEND_MDB2) { - //MDB2 uses or emulates limits & offset internally - self::$MDB2->setLimit($limit, $offset); + //PDO does not handle limit and offset. + //FIXME: check limit notation for other dbs + //the following sql thus might needs to take into account db ways of representing it + //(oracle has no LIMIT / OFFSET) + $limit = (int)$limit; + $limitsql = ' LIMIT ' . $limit; + if (!is_null($offset)) { + $offset = (int)$offset; + $limitsql .= ' OFFSET ' . $offset; + } + //insert limitsql + if (substr($query, -1) == ';') { //if query ends with ; + $query = substr($query, 0, -1) . $limitsql . ';'; } else { - //PDO does not handle limit and offset. - //FIXME: check limit notation for other dbs - //the following sql thus might needs to take into account db ways of representing it - //(oracle has no LIMIT / OFFSET) - $limit = (int)$limit; - $limitsql = ' LIMIT ' . $limit; - if (!is_null($offset)) { - $offset = (int)$offset; - $limitsql .= ' OFFSET ' . $offset; - } - //insert limitsql - if (substr($query, -1) == ';') { //if query ends with ; - $query = substr($query, 0, -1) . $limitsql . ';'; - } else { - $query.=$limitsql; - } + $query.=$limitsql; } + } else { + if (isset(self::$preparedQueries[$query])) { + return self::$preparedQueries[$query]; + } } + $rawQuery = $query; // Optimize the query $query = self::processQuery( $query ); @@@ -190,14 -362,13 +223,13 @@@ try{ $result=self::$connection->prepare($query); }catch(PDOException $e) { - $entry = 'DB Error: "'.$e->getMessage().'"
'; - $entry .= 'Offending command was: '.htmlentities($query).'
'; - OC_Log::write('core', $entry, OC_Log::FATAL); - error_log('DB error: '.$entry); - OC_Template::printErrorPage( $entry ); + throw new DatabaseException($e->getMessage(), $query); } - $result=new PDOStatementWrapper($result); + $result=new DoctrineStatementWrapper($result); } + if (is_null($limit) || $limit == -1) { + self::$preparedQueries[$rawQuery] = $result; + } return $result; } @@@ -275,9 -474,41 +307,10 @@@ * http://www.sqlite.org/lang_createtable.html * http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm */ - if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't - $content = str_replace( '0000-00-00 00:00:00', 'CURRENT_TIMESTAMP', $content ); - } + if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't + $content = str_replace( '0000-00-00 00:00:00', + 'CURRENT_TIMESTAMP', $content ); + } - - file_put_contents( $file2, $content ); - - // Try to create tables - $definition = self::$schema->parseDatabaseDefinitionFile( $file2 ); - - //clean up memory - unlink( $file2 ); - - // Die in case something went wrong - if( $definition instanceof MDB2_Schema_Error ) { - OC_Template::printErrorPage( $definition->getMessage().': '.$definition->getUserInfo() ); - } - if(OC_Config::getValue('dbtype', 'sqlite')==='oci') { - unset($definition['charset']); //or MDB2 tries SHUTDOWN IMMEDIATE - $oldname = $definition['name']; - $definition['name']=OC_Config::getValue( "dbuser", $oldname ); - } - - // we should never drop a database - $definition['overwrite'] = false; - - $ret=self::$schema->createDatabase( $definition ); - - // Die in case something went wrong - if( $ret instanceof MDB2_Error ) { - OC_Template::printErrorPage( self::$MDB2->getDebugOutput().' '.$ret->getMessage() . ': ' - . $ret->getUserInfo() ); - } - - return true; } /** @@@ -286,14 -517,27 +319,14 @@@ * @return bool */ public static function updateDbFromStructure($file) { - $CONFIG_DBTABLEPREFIX = OC_Config::getValue( "dbtableprefix", "oc_" ); - $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); - - self::connectScheme(); - - // read file - $content = file_get_contents( $file ); - - $previousSchema = self::$schema->getDefinitionFromDatabase(); - if (PEAR::isError($previousSchema)) { - $error = $previousSchema->getMessage(); - $detail = $previousSchema->getDebugInfo(); - $message = 'Failed to get existing database structure for updating ('.$error.', '.$detail.')'; - OC_Log::write('core', $message, OC_Log::FATAL); - throw new Exception($message); + self::connectDoctrine(); + try { + $result = OC_DB_Schema::updateDbFromStructure(self::$connection, $file); + } catch (Exception $e) { + OC_Log::write('core', 'Failed to update database structure ('.$e.')', OC_Log::FATAL); - return false; ++ throw $e; } - - // Make changes and save them to an in-memory file - $file2 = 'static://db_scheme'; - $content = str_replace( '*dbname*', $previousSchema['name'], $content ); - $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content ); + return $result; /* FIXME: use CURRENT_TIMESTAMP for all databases. mysql supports it as a default for DATETIME since 5.6.5 [1] * as a fallback we could use 0000-01-01 00:00:00 everywhere * [1] http://bugs.mysql.com/bug.php?id=27645 @@@ -303,8 -547,44 +336,9 @@@ * http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm */ if( $CONFIG_DBTYPE == 'pgsql' ) { //mysql support it too but sqlite doesn't - $content = str_replace( '0000-00-00 00:00:00', 'CURRENT_TIMESTAMP', $content ); + $content = str_replace( '0000-00-00 00:00:00', + 'CURRENT_TIMESTAMP', $content ); } - file_put_contents( $file2, $content ); - $op = self::$schema->updateDatabase($file2, $previousSchema, array(), false); - - //clean up memory - unlink( $file2 ); - - if (PEAR::isError($op)) { - $error = $op->getMessage(); - $detail = $op->getDebugInfo(); - $message = 'Failed to update database structure ('.$error.', '.$detail.')'; - OC_Log::write('core', $message, OC_Log::FATAL); - throw new Exception($message); - } - return true; - } - - /** - * @brief connects to a MDB2 database scheme - * @returns bool - * - * Connects to a MDB2 database scheme - */ - private static function connectScheme() { - // We need a mdb2 database connection - self::connectMDB2(); - self::$MDB2->loadModule('Manager'); - self::$MDB2->loadModule('Reverse'); - - // Connect if this did not happen before - if(!self::$schema) { - require_once 'MDB2/Schema.php'; - self::$schema=MDB2_Schema::factory(self::$MDB2); - } - - return true; } /**