Web installation support for Oracle.
authorJure Kajzer <freakolowsky@users.mediawiki.org>
Mon, 8 Jun 2009 18:30:27 +0000 (18:30 +0000)
committerJure Kajzer <freakolowsky@users.mediawiki.org>
Mon, 8 Jun 2009 18:30:27 +0000 (18:30 +0000)
RELEASE-NOTES
config/index.php
includes/Defines.php
includes/db/DatabaseOracle.php
maintenance/ora/tables.sql
maintenance/ora/user.sql

index 6048e88..eac847a 100644 (file)
@@ -38,7 +38,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * (bug 10837) $wgVariant is a user variant selected in the user's preferences
   if the $wgContLang does not have variant, then the $wgLang is used instead.
 * Oracle: maintenance/ora/user.sql script for creating DB user on oracle with
-  appropriate privileges
+  appropriate privileges. Creating this user with web-install page requires
+  oci8.privileged_connect set to On in php.ini.
 
 === New features in 1.16 ===
 
index 96e8a14..1367b52 100644 (file)
@@ -87,6 +87,12 @@ $ourdb['ibm_db2']['compile']    = 'ibm_db2';
 $ourdb['ibm_db2']['bgcolor']    = '#ffeba1';
 $ourdb['ibm_db2']['rootuser']   = 'db2admin';
 
+$ourdb['oracle']['fullname']   = 'Oracle';
+$ourdb['oracle']['havedriver'] = 0;
+$ourdb['oracle']['compile']    = 'oci8';
+$ourdb['oracle']['bgcolor']    = '#ffeba1';
+$ourdb['oracle']['rootuser']   = '';
+
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
@@ -634,6 +640,11 @@ print "<li style='font-weight:bold;color:green;font-size:110%'>Environment check
        $conf->DBmwschema   = importPost( "DBmwschema",  "mediawiki" );
        $conf->DBcataloged  = importPost( "DBcataloged",  "cataloged" );
 
+       // Oracle specific
+       $conf->DBprefix_ora     = importPost( "DBprefix_ora" );
+       $conf->DBdefTS_ora     = importPost( "DBdefTS_ora", "USERS" );
+       $conf->DBtempTS_ora     = importPost( "DBtempTS_ora", "TEMP" );
+
        $conf->ShellLocale = getShellLocale( $conf->LanguageCode );
 
 /* Check for validity */
@@ -659,6 +670,9 @@ if( !preg_match( '/^[A-Za-z_0-9]*$/', $conf->DBprefix ) ) {
 } else {
        untaint( $conf->DBprefix, TC_MYSQL );
 }
+if( !preg_match( '/^[A-Za-z_0-9]*$/', $conf->DBprefix_ora ) ) {
+       $errs["DBprefix_ora"] = "Invalid table prefix";
+}
 
 error_reporting( E_ALL );
 
@@ -804,6 +818,9 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) {
                if( $conf->DBprefix2 != '' ) {
                        // For MSSQL
                        $wgDBprefix = $conf->DBprefix2;
+               } elseif( $conf->DBprefix_ora != '' ) {
+                       // For Oracle
+                       $wgDBprefix = $conf->DBprefix_ora;
                }
 
                ## DB2 specific:
@@ -945,6 +962,46 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) {
                        }
                        if (is_callable(array($wgDatabase, 'initial_setup'))) $wgDatabase->initial_setup('', $wgDBname);
                        echo "ok</li>\n";
+               } elseif ( $conf->DBtype == 'oracle' ) {
+                       echo "<li>Attempting to connect to database \"" . htmlspecialchars( $wgDBname ) ."\"</li>";
+                       $wgDatabase = $dbc->newFromParams('DUMMY', $wgDBuser, $wgDBpassword, $wgDBname, 1);
+                       if (!$wgDatabase->isOpen()) {
+                               $ok = true;
+                               echo "<li>Connect failed.</li>";
+                               if ($useRoot) {
+                                       if (ini_get('oci8.privileged_connect') === false) {
+                                               echo "<li>Privileged connect disabled, please set oci8.privileged_connect or run maintenance/ora/user.sql script manually prior to continuing.</li>";
+                                               $ok = false;
+                                       } else {
+                                               $wgDBadminuser = $conf->RootUser;
+                                               $wgDBadminpassword = $conf->RootPW;
+                                               echo "<li>Attempting to create DB user.</li>";
+                                               $wgDatabase = $dbc->newFromParams('DUMMY', $wgDBadminuser, $wgDBadminpassword, $wgDBname, 1, 64);
+                                               if ($wgDatabase->isOpen()) {
+                                                       $wgDBOracleDefTS = $conf->DBdefTS_ora;
+                                                       $wgDBOracleTempTS = $conf->DBtempTS_ora;
+                                                       dbsource( "../maintenance/ora/user.sql", $wgDatabase );
+                                               } else {
+                                                       echo "<li>Invalid database superuser, please supply a valid superuser account.</li>";
+                                                       echo "<li>ERR: ".print_r(oci_error(), true)."</li>";
+                                                       $ok = false;
+                                               }
+                                       }
+                               } else {
+                                       echo "<li>Database superuser missing, please supply a valid superuser account.</li>";
+                                       $ok = false;
+                               }
+                               if (!$ok) {
+                                       $errs["RootUser"] = "Check username";
+                                       $errs["RootPW"] = "and password";
+                               } else {
+                                       echo "<li>Attempting to connect to database with new user \"" . htmlspecialchars( $wgDBname ) ."\"</li>";
+                                       $wgDatabase = $dbc->newFromParams('DUMMY', $wgDBuser, $wgDBpassword, $wgDBname, 1);
+                               }
+                       }
+                       if ($ok) {
+                               $myver = $wgDatabase->getServerVersion();
+                       }
                } else { # not mysql
                        error_reporting( E_ALL );
                        $wgSuperUser = '';
@@ -1578,6 +1635,19 @@ if( count( $errs ) ) {
        </div>
        </fieldset>
 
+       <?php database_switcher('oracle'); ?>
+       <div class="config-input"><?php aField( $conf, "DBprefix_ora", "Database table prefix:" ); ?></div>
+       <div class="config-desc">
+               <p>If you need to share one database between multiple wikis, or
+               between MediaWiki and another web application, you may choose to
+               add a prefix to all the table names to avoid conflicts.</p>
+
+               <p>Avoid exotic characters; something like <tt>mw_</tt> is good.</p>
+       </div>
+       <div class="config-input"><?php aField( $conf, "DBdefTS_ora", "Default tablespace:" ); ?></div>
+       <div class="config-input"><?php aField( $conf, "DBtempTS_ora", "Temporary tablespace:" ); ?></div>
+       </fieldset>
+
        <div class="config-input" style="padding:2em 0 3em">
                <label class='column'>&nbsp;</label>
                <input type="submit" value="Install MediaWiki!" class="btn-install" />
@@ -1753,6 +1823,10 @@ function writeLocalSettings( $conf ) {
 \$wgDBport_db2       = \"{$slconf['DBport_db2']}\";
 \$wgDBmwschema       = \"{$slconf['DBmwschema']}\";
 \$wgDBcataloged      = \"{$slconf['DBcataloged']}\";";
+       } elseif( $conf->DBtype == 'oracle' ) {
+               $dbsettings =
+"# Oracle specific settings
+\$wgDBprefix         = \"{$slconf['DBprefix']}\";";
        } else {
                // ummm... :D
                $dbsettings = '';
index 8de6c5a..67d9ad5 100644 (file)
@@ -18,6 +18,7 @@ define( 'DBO_IGNORE', 4 );
 define( 'DBO_TRX', 8 );
 define( 'DBO_DEFAULT', 16 );
 define( 'DBO_PERSISTENT', 32 );
+define( 'DBO_SYSDBA', 64 ); //for oracle maintenance
 /**#@-*/
 
 # Valid database indexes
index a0700db..0d3effe 100644 (file)
@@ -217,14 +217,15 @@ class DatabaseOracle extends Database {
                $this->mDBname = $dbName;
 
                if (!strlen($user)) { ## e.g. the class is being loaded
-                       return;
+               return;
                }
 
                //error_reporting( E_ALL ); //whoever had this bright idea
+               $session_mode = $this->mFlags & DBO_SYSDBA ? OCI_SYSDBA : OCI_DEFAULT;
                if ( $this->mFlags & DBO_DEFAULT )
-                       $this->mConn = oci_new_connect($user, $password, $dbName);
+                       $this->mConn = oci_new_connect($user, $password, $dbName, null, $session_mode);
                else
-                       $this->mConn = oci_connect($user, $password, $dbName);
+                       $this->mConn = oci_connect($user, $password, $dbName, null, $session_mode);
 
                if ($this->mConn == false) {
                        wfDebug("DB connection error\n");
@@ -832,6 +833,101 @@ class DatabaseOracle extends Database {
                return $sql;
        }
 
+       /* defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}'; */
+       function sourceStream( $fp, $lineCallback = false, $resultCallback = false ) {
+               $cmd = "";
+               $done = false;
+               $dollarquote = false;
+               
+               $replacements = array();
+
+               while ( ! feof( $fp ) ) {
+                       if ( $lineCallback ) {
+                               call_user_func( $lineCallback );
+                       }
+                       $line = trim( fgets( $fp, 1024 ) );
+                       $sl = strlen( $line ) - 1;
+
+                       if ( $sl < 0 ) { continue; }
+                       if ( '-' == $line{0} && '-' == $line{1} ) { continue; }
+
+                       // Allow dollar quoting for function declarations
+                       if (substr($line,0,8) == '/*$mw$*/') {
+                               if ($dollarquote) {
+                                       $dollarquote = false;
+                                       $done = true;
+                               }
+                               else {
+                                       $dollarquote = true;
+                               }
+                       }
+                       else if (!$dollarquote) {
+                               if ( ';' == $line{$sl} && ($sl < 2 || ';' != $line{$sl - 1})) {
+                                       $done = true;
+                                       $line = substr( $line, 0, $sl );
+                               }
+                       }
+
+                       if ( '' != $cmd ) { $cmd .= ' '; }
+                       $cmd .= "$line\n";
+
+                       if ( $done ) {
+                               $cmd = str_replace(';;', ";", $cmd);
+                               if (strtolower(substr($cmd, 0, 6)) == 'define' ) {
+                                       if (preg_match('/^define\s*([^\s=]*)\s*=\s*\'\{\$([^\}]*)\}\'/', $cmd, $defines)) {
+                                               $replacements[$defines[2]] = $defines[1];
+                                       }
+                               } else {
+                                       foreach ( $replacements as $mwVar=>$scVar ) {
+                                               $cmd = str_replace( '&' . $scVar . '.', '{$'.$mwVar.'}', $cmd );
+                                       }
+
+                                       $cmd = $this->replaceVars( $cmd );
+                                       $res = $this->query( $cmd, __METHOD__ );
+                                       if ( $resultCallback ) {
+                                               call_user_func( $resultCallback, $res, $this );
+                                       }
+       
+                                       if ( false === $res ) {
+                                               $err = $this->lastError();
+                                               return "Query \"{$cmd}\" failed with error code \"$err\".\n";
+                                       }
+                               }
+
+                               $cmd = '';
+                               $done = false;
+                       }
+               }
+               return true;
+       }
+
+       function setup_database() {
+               global $wgVersion, $wgDBmwschema, $wgDBts2schema, $wgDBport, $wgDBuser;
+               
+               echo "<li>Creating DB objects</li>\n";
+               $res = dbsource( "../maintenance/ora/tables.sql", $this);
+               
+               // Avoid the non-standard "REPLACE INTO" syntax
+               echo "<li>Populating table interwiki</li>\n";
+               $f = fopen( "../maintenance/interwiki.sql", 'r' );
+               if ($f == false ) {
+                       dieout( "<li>Could not find the interwiki.sql file</li>");
+               }
+               
+               //do it like the postgres :D
+               $SQL = "INSERT INTO interwiki(iw_prefix,iw_url,iw_local) VALUES ";
+               while ( ! feof( $f ) ) {
+                       $line = fgets($f,1024);
+                       $matches = array();
+                       if (!preg_match('/^\s*(\(.+?),(\d)\)/', $line, $matches)) {
+                               continue;
+                       }
+                       $this->query("$SQL $matches[1],$matches[2])");
+               }
+
+               echo "<li>Table interwiki successfully populated</li>\n";
+       }
+
        function strencode($s) {
                return str_replace("'", "''", $s);
        }
@@ -967,6 +1063,26 @@ class DatabaseOracle extends Database {
                return $this->mServer;
        }
        
+       public function replaceVars( $ins ) {
+               $varnames = array('wgDBprefix');
+               if ($this->mFlags & DBO_SYSDBA) {
+                       $varnames[] = 'wgDBOracleDefTS';
+                       $varnames[] = 'wgDBOracleTempTS';
+               }
+
+               // Ordinary variables
+               foreach ( $varnames as $var ) {
+                       if( isset( $GLOBALS[$var] ) ) {
+                               $val = addslashes( $GLOBALS[$var] ); // FIXME: safety check?
+                               $ins = str_replace( '{$' . $var . '}', $val, $ins );
+                               $ins = str_replace( '/*$' . $var . '*/`', '`' . $val, $ins );
+                               $ins = str_replace( '/*$' . $var . '*/', $val, $ins );
+                       }
+               }
+
+               return parent::replaceVars($ins);
+       }
+
        /** 
         * No-op lock functions
         */
index 61211fb..d7e6a1e 100644 (file)
@@ -1,4 +1,5 @@
-DEFINE mw_prefix='';
+-- defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}';
+define mw_prefix='{$wgDBprefix}';
 
 
 CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0;
@@ -70,12 +71,13 @@ CREATE UNIQUE INDEX &mw_prefix.page_u01 ON &mw_prefix.page (page_namespace,page_
 CREATE INDEX &mw_prefix.page_i01 ON &mw_prefix.page (page_random);
 CREATE INDEX &mw_prefix.page_i02 ON &mw_prefix.page (page_len);
 
+/*$mw$*/
 CREATE TRIGGER &mw_prefix.page_set_random BEFORE INSERT ON &mw_prefix.page
-        FOR EACH ROW WHEN (new.page_random IS NULL)
-        BEGIN
-                SELECT dbms_random.value INTO :NEW.page_random FROM dual;
-        END;
-/
+       FOR EACH ROW WHEN (new.page_random IS NULL)
+BEGIN
+       SELECT dbms_random.value INTO :NEW.page_random FROM dual;
+END;
+/*$mw$*/
 
 CREATE SEQUENCE rev_rev_id_val;
 CREATE TABLE &mw_prefix.revision (
@@ -463,7 +465,9 @@ CREATE UNIQUE INDEX &mw_prefix.querycache_info_u01 ON &mw_prefix.querycache_info
 CREATE TABLE &mw_prefix.redirect (
   rd_from       NUMBER  NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
   rd_namespace  NUMBER NOT NULL,
-  rd_title      VARCHAR2(255)     NOT NULL
+  rd_title      VARCHAR2(255)     NOT NULL,
+  rd_interwiki  VARCHAR2(32),
+  rd_fragment   VARCHAR2(255)
 );
 CREATE INDEX &mw_prefix.redirect_i01 ON &mw_prefix.redirect (rd_namespace,rd_title,rd_from);
 
@@ -571,6 +575,7 @@ nonuniq NUMBER(1)
 );
 ALTER TABLE &mw_prefix.wiki_field_info_full ADD CONSTRAINT &mw_prefix.wiki_field_info_full_pk PRIMARY KEY (table_name, column_name);
 
+/*$mw$*/
 CREATE PROCEDURE &mw_prefix.fill_wiki_info IS
        BEGIN
                DELETE      &mw_prefix.wiki_field_info_full;
@@ -619,12 +624,17 @@ CREATE PROCEDURE &mw_prefix.fill_wiki_info IS
                END LOOP;
                COMMIT;
 END;
+/*$mw$*/
 
+/*$mw$*/
 BEGIN 
        &mw_prefix.fill_wiki_info;
 END;
+/*$mw$*/
 
+/*$mw$*/
 CREATE OR REPLACE FUNCTION BITOR (x IN NUMBER, y IN NUMBER) RETURN NUMBER AS
 BEGIN
   RETURN (x + y - BITAND(x, y));
 END;
+/*$mw$*/
index d5323d7..e3f377f 100644 (file)
@@ -1,13 +1,15 @@
-define WIKI_USER=&1
-define WIKI_PASS=&2
-define DEF_TS=&3
-define TEMP_TS=&4
-create user &&wiki_user identified by &&wiki_pass default tablespace &&def_ts temporary tablespace &&temp_ts quota unlimited on &&def_ts;
-grant connect, resource to &&wiki_user;
-grant alter session to &&wiki_user;
-grant ctxapp to &&wiki_user;
-grant execute on ctx_ddl to &&wiki_user;
-grant create view to &&wiki_user;
-grant create synonym to &&wiki_user;
-grant create table to &&wiki_user;
-grant create sequence to &&wiki_user;
+-- defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}';
+define wiki_user='{$wgDBuser}';
+define wiki_pass='{$wgDBpassword}';
+define def_ts='{$wgDBOracleDefTS}';
+define temp_ts='{$wgDBOracleTempTS}';
+
+create user &wiki_user. identified by &wiki_pass. default tablespace &def_ts. temporary tablespace &temp_ts. quota unlimited on &def_ts.;
+grant connect, resource to &wiki_user.;
+grant alter session to &wiki_user.;
+grant ctxapp to &wiki_user.;
+grant execute on ctx_ddl to &wiki_user.;
+grant create view to &wiki_user.;
+grant create synonym to &wiki_user.;
+grant create table to &wiki_user.;
+grant create sequence to &wiki_user.;