From 795e78809f55be762fb07d9a179bbdffa7aefbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Mon, 30 Jul 2012 20:53:21 +0200 Subject: [PATCH] add oracle to install & setup --- core/js/setup.js | 7 ++ core/templates/installation.php | 25 +++- lib/db.php | 46 ++++++-- lib/setup.php | 198 +++++++++++++++++++++++++++++++- 4 files changed, 261 insertions(+), 15 deletions(-) diff --git a/core/js/setup.js b/core/js/setup.js index 6e056cc90d..23c705a068 100644 --- a/core/js/setup.js +++ b/core/js/setup.js @@ -4,6 +4,7 @@ $(document).ready(function() { sqlite:!!$('#hasSQLite').val(), mysql:!!$('#hasMySQL').val(), postgresql:!!$('#hasPostgreSQL').val(), + oracle:!!$('#hasOracle').val(), } $('#selectDbType').buttonset(); @@ -34,6 +35,12 @@ $(document).ready(function() { $('#dbhost').show(250); $('#dbhostlabel').show(250); }); + + $('#oci').click(function() { + $('#use_other_db').slideDown(250); + $('#dbhost').show(250); + $('#dbhostlabel').show(250); + }); $('input[checked]').trigger('click'); diff --git a/core/templates/installation.php b/core/templates/installation.php index 4558f97bc0..1a05c3fb76 100644 --- a/core/templates/installation.php +++ b/core/templates/installation.php @@ -1,6 +1,7 @@ '> '> '> +'>
@@ -40,7 +41,7 @@
- + t( 'Configure the database' ); ?>
@@ -56,7 +57,7 @@ - +

MySQL t( 'will be used' ); ?>.

@@ -66,7 +67,7 @@ - +

PostgreSQL t( 'will be used' ); ?>.

@@ -74,6 +75,16 @@ /> + + + +

Oracle t( 'will be used' ); ?>.

+ + + + /> + +
@@ -92,6 +103,14 @@

+ +
+

+ + +

+
+

diff --git a/lib/db.php b/lib/db.php index 08bd06df95..a2dbc5dfac 100644 --- a/lib/db.php +++ b/lib/db.php @@ -44,15 +44,18 @@ class OC_DB { * @return BACKEND_MDB2 or BACKEND_PDO */ private static function getDBBackend(){ - $backend=self::BACKEND_MDB2; if(class_exists('PDO') && OC_Config::getValue('installed', false)){//check if we can use PDO, else use MDB2 (instalation always needs to be done my mdb2) $type = OC_Config::getValue( "dbtype", "sqlite" ); + if($type=='oci') { //oracle also always needs mdb2 + return self::BACKEND_MDB2; + } if($type=='sqlite3') $type='sqlite'; $drivers=PDO::getAvailableDrivers(); if(array_search($type,$drivers)!==false){ - $backend=self::BACKEND_PDO; + return self::BACKEND_PDO; } } + return self::BACKEND_MDB2; } /** @@ -129,7 +132,14 @@ class OC_DB { $dsn='pgsql:dbname='.$name.';host='.$host; } break; - } + case 'oci': + if ($port) { + $dsn = 'oci:dbname=//' . $host . ':' . $port . '/' . $name; + } else { + $dsn = 'oci:dbname=//' . $host . '/' . $name; + } + break; + } try{ self::$PDO=new PDO($dsn,$user,$pass,$opts); }catch(PDOException $e){ @@ -345,9 +355,17 @@ class OC_DB { $file2 = 'static://db_scheme'; $content = str_replace( '*dbname*', $CONFIG_DBNAME, $content ); $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $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 ); - } + /* FIXME: REMOVE this commented code + * actually mysql, postgresql, sqlite and oracle support CUURENT_TIMESTAMP + * http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html + * http://www.postgresql.org/docs/8.1/static/functions-datetime.html + * 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 ); + } + */ file_put_contents( $file2, $content ); // Try to create tables @@ -363,10 +381,17 @@ class OC_DB { // if(OC_Config::getValue('dbtype','sqlite')=='sqlite'){ // $definition['overwrite']=true;//always overwrite for sqlite // } + 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 ); + } + $ret=self::$schema->createDatabase( $definition ); // Die in case something went wrong if( $ret instanceof MDB2_Error ){ + echo (self::$MDB2->getDebugOutput()); die ($ret->getMessage() . ': ' . $ret->getUserInfo()); } @@ -397,9 +422,16 @@ class OC_DB { $file2 = 'static://db_scheme'; $content = str_replace( '*dbname*', $previousSchema['name'], $content ); $content = str_replace( '*dbprefix*', $CONFIG_DBTABLEPREFIX, $content ); + /* FIXME: REMOVE this commented code + * actually mysql, postgresql, sqlite and oracle support CUURENT_TIMESTAMP + * http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html + * http://www.postgresql.org/docs/8.1/static/functions-datetime.html + * 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 ); } + */ file_put_contents( $file2, $content ); $op = self::$schema->updateDatabase($file2, $previousSchema, array(), false); @@ -464,7 +496,7 @@ class OC_DB { }elseif( $type == 'mysql' ){ $query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query ); $query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query ); - }elseif( $type == 'pgsql' ){ + }elseif( $type == 'pgsql' || $type == 'oci' ){ $query = str_replace( '`', '"', $query ); $query = str_replace( 'NOW()', 'CURRENT_TIMESTAMP', $query ); $query = str_replace( 'now()', 'CURRENT_TIMESTAMP', $query ); diff --git a/lib/setup.php b/lib/setup.php index 59c3aefbf1..bf7b6e3682 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -3,11 +3,13 @@ $hasSQLite = (is_callable('sqlite_open') or class_exists('SQLite3')); $hasMySQL = is_callable('mysql_connect'); $hasPostgreSQL = is_callable('pg_connect'); +$hasOracle = is_callable('oci_connect'); $datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); $opts = array( 'hasSQLite' => $hasSQLite, 'hasMySQL' => $hasMySQL, 'hasPostgreSQL' => $hasPostgreSQL, + 'hasOracle' => $hasOracle, 'directory' => $datadir, 'errors' => array(), ); @@ -46,11 +48,14 @@ class OC_Setup { $error[] = 'Specify a data folder.'; } - if($dbtype=='mysql' or $dbtype=='pgsql') { //mysql and postgresql needs more config options + if($dbtype=='mysql' or $dbtype == 'pgsql' or $dbtype == 'oci') { //mysql and postgresql needs more config options if($dbtype=='mysql') $dbprettyname = 'MySQL'; - else - $dbprettyname = 'PostgreSQL'; + else if($dbtype=='pgsql') + $dbprettyname = 'PostgreSQL'; + else + $dbprettyname = 'Oracle'; + if(empty($options['dbuser'])) { $error[] = "$dbprettyname enter the database username."; @@ -108,7 +113,7 @@ class OC_Setup { if(mysql_query($query, $connection)) { //use the admin login data for the new database user - //add prefix to the mysql user name to prevent collissions + //add prefix to the mysql user name to prevent collisions $dbusername=substr('oc_'.$username,0,16); if($dbusername!=$oldUser){ //hash the password so we don't need to store the admin config in the config file @@ -172,7 +177,7 @@ class OC_Setup { if($result and pg_num_rows($result) > 0) { //use the admin login data for the new database user - //add prefix to the postgresql user name to prevent collissions + //add prefix to the postgresql user name to prevent collisions $dbusername='oc_'.$username; //create a new password so we don't need to store the admin config in the config file $dbpassword=md5(time()); @@ -218,6 +223,116 @@ class OC_Setup { } } } + elseif($dbtype == 'oci') { + $dbuser = $options['dbuser']; + $dbpass = $options['dbpass']; + $dbname = $options['dbname']; + $dbtablespace = $options['dbtablespace']; + $dbhost = $options['dbhost']; + $dbtableprefix = isset($options['dbtableprefix']) ? $options['dbtableprefix'] : 'oc_'; + OC_CONFIG::setValue('dbname', $dbname); + OC_CONFIG::setValue('dbtablespace', $dbtablespace); + OC_CONFIG::setValue('dbhost', $dbhost); + OC_CONFIG::setValue('dbtableprefix', $dbtableprefix); + + $e_host = addslashes($dbhost); + $e_dbname = addslashes($dbname); + //check if the database user has admin right + $connection_string = '//'.$e_host.'/'.$e_dbname; + $connection = @oci_connect($dbuser, $dbpass, $connection_string); + if(!$connection) { + $e = oci_error(); + $error[] = array( + 'error' => 'Oracle username and/or password not valid', + 'hint' => 'You need to enter either an existing account or the administrator.' + ); + return $error; + } else { + //check for roles creation rights in oracle + + $query="SELECT count(*) FROM user_role_privs, role_sys_privs WHERE user_role_privs.granted_role = role_sys_privs.role AND privilege = 'CREATE ROLE'"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry='DB Error: "'.oci_last_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + $result = oci_execute($stmt); + if($result) { + $row = oci_fetch_row($stmt); + } + if($result and $row[0] > 0) { + //use the admin login data for the new database user + + //add prefix to the oracle user name to prevent collisions + $dbusername='oc_'.$username; + //create a new password so we don't need to store the admin config in the config file + $dbpassword=md5(time().$dbpass); + + //oracle passwords are treated as identifiers: + // must start with aphanumeric char + // needs to be shortened to 30 bytes, as the two " needed to escape the identifier count towards the identifier length. + $dbpassword=substr($dbpassword, 0, 30); + + self::oci_createDBUser($dbusername, $dbpassword, $dbtablespace, $connection); + + OC_CONFIG::setValue('dbuser', $dbusername); + OC_CONFIG::setValue('dbname', $dbusername); + OC_CONFIG::setValue('dbpassword', $dbpassword); + + //create the database not neccessary, oracle implies user = schema + //self::oci_createDatabase($dbname, $dbusername, $connection); + } else { + + OC_CONFIG::setValue('dbuser', $dbuser); + OC_CONFIG::setValue('dbpassword', $dbpass); + + //create the database not neccessary, oracle implies user = schema + //self::oci_createDatabase($dbname, $dbuser, $connection); + } + + //FIXME check tablespace exists: select * from user_tablespaces + + // the connection to dbname=oracle is not needed anymore + oci_close($connection); + + // connect to the oracle database (schema=$dbuser) an check if the schema needs to be filled + $dbuser = OC_CONFIG::getValue('dbuser'); + //$dbname = OC_CONFIG::getValue('dbname'); + $dbpass = OC_CONFIG::getValue('dbpassword'); + + $e_host = addslashes($dbhost); + $e_dbname = addslashes($dbname); + + $connection_string = '//'.$e_host.'/'.$e_dbname; + $connection = @oci_connect($dbuser, $dbpass, $connection_string); + if(!$connection) { + $error[] = array( + 'error' => 'Oracle username and/or password not valid', + 'hint' => 'You need to enter either an existing account or the administrator.' + ); + return $error; + } else { + $query = "SELECT count(*) FROM user_tables WHERE table_name = :un"; + $stmt = oci_parse($connection, $query); + $un = $dbtableprefix.'users'; + oci_bind_by_name($stmt, ':un', $un); + if (!$stmt) { + $entry='DB Error: "'.oci_last_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + $result = oci_execute($stmt); + + if($result) { + $row = oci_fetch_row($stmt); + } + if(!$result or $row[0]==0) { + OC_DB::createDbFromStructure('db_structure.xml'); + } + } + } + } else { //delete the old sqlite database first, might cause infinte loops otherwise if(file_exists("$datadir/owncloud.db")){ @@ -307,6 +422,79 @@ class OC_Setup { echo($entry); } } + /** + * + * @param String $name + * @param String $password + * @param String $tablespace + * @param resource $connection + */ + private static function oci_createDBUser($name, $password, $tablespace, $connection) { + + $query = "SELECT * FROM all_users WHERE USERNAME = :un"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + oci_bind_by_name($stmt, ':un', $name); + $result = oci_execute($stmt); + if(!$result) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + + if(! oci_fetch_row($stmt)) { + //user does not exists let's create it :) + //password must start with alphabetic character in oracle + $query = 'CREATE USER '.$name.' IDENTIFIED BY "'.$password.'" DEFAULT TABLESPACE '.$tablespace; //TODO set default tablespace + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + //oci_bind_by_name($stmt, ':un', $name); + $result = oci_execute($stmt); + if(!$result) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.', name:'.$name.', password:'.$password.'
'; + echo($entry); + } + } else { // change password of the existing role + $query = "ALTER USER :un IDENTIFIED BY :pw"; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + oci_bind_by_name($stmt, ':un', $name); + oci_bind_by_name($stmt, ':pw', $password); + $result = oci_execute($stmt); + if(!$result) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + } + // grant neccessary roles + $query = 'GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, CREATE TRIGGER, UNLIMITED TABLESPACE TO '.$name; + $stmt = oci_parse($connection, $query); + if (!$stmt) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.'
'; + echo($entry); + } + $result = oci_execute($stmt); + if(!$result) { + $entry='DB Error: "'.oci_error($connection).'"
'; + $entry.='Offending command was: '.$query.', name:'.$name.', password:'.$password.'
'; + echo($entry); + } + } /** * create .htaccess files for apache hosts