Oracle database abstraction updated.
authorJure Kajzer <freakolowsky@users.mediawiki.org>
Fri, 5 Jun 2009 11:45:32 +0000 (11:45 +0000)
committerJure Kajzer <freakolowsky@users.mediawiki.org>
Fri, 5 Jun 2009 11:45:32 +0000 (11:45 +0000)
Rewriten tables.sql, added user.sql (creating db user with privileges)
Fixed epoch in Special Ancientpages and Unusedimages
Timestamp default format altered in db abstraction and changed wfTimestamp function
SearchOracle changed to return empty resultset on empty term search (query error in oracle)
TODO: Maintenance scripts update

RELEASE-NOTES
includes/GlobalFunctions.php
includes/SearchOracle.php
includes/db/DatabaseOracle.php
includes/specials/SpecialAncientpages.php
includes/specials/SpecialUnusedimages.php
maintenance/ora/tables.sql
maintenance/ora/user.sql [new file with mode: 0644]

index 2f6ae1e..974e427 100644 (file)
@@ -37,6 +37,8 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
   which was already effectively treating the namespace as if it had subpages.
 * (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
 
 === New features in 1.16 ===
 
index 4e12e72..f1009ac 100644 (file)
@@ -1831,8 +1831,8 @@ function wfTimestamp($outputtype=TS_UNIX,$ts=0) {
        } elseif (preg_match('/^\d{1,13}$/D',$ts)) {
                # TS_UNIX
                $uts = $ts;
-       } elseif (preg_match('/^\d{1,2}-...-\d\d(?:\d\d)? \d\d\.\d\d\.\d\d/', $ts)) {
-               # TS_ORACLE
+       } elseif (preg_match('/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts)) {
+               # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
                $uts = strtotime(preg_replace('/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
                                str_replace("+00:00", "UTC", $ts)));
        } elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da)) {
@@ -1869,7 +1869,8 @@ function wfTimestamp($outputtype=TS_UNIX,$ts=0) {
                case TS_RFC2822:
                        return gmdate( 'D, d M Y H:i:s', $uts ) . ' GMT';
                case TS_ORACLE:
-                       return gmdate( 'd-M-y h.i.s A', $uts) . ' +00:00';
+                       return gmdate( 'd-m-Y H:i:s.000000', $uts);
+                       //return gmdate( 'd-M-y h.i.s A', $uts) . ' +00:00';
                case TS_POSTGRES:
                        return gmdate( 'Y-m-d H:i:s', $uts) . ' GMT';
                case TS_DB2:
index edb39a5..b54fb85 100644 (file)
@@ -38,6 +38,9 @@ class SearchOracle extends SearchEngine {
         * @return OracleSearchResultSet
         */
        function searchText( $term ) {
+               if ($term == '')
+                       return new OracleSearchResultSet(false, '');
+               
                $resultSet = $this->db->resultObject($this->db->query($this->getQuery($this->filter($term), true)));
                return new OracleSearchResultSet($resultSet, $this->searchTerms);
        }
@@ -49,6 +52,9 @@ class SearchOracle extends SearchEngine {
         * @return ORacleSearchResultSet
         */
        function searchTitle($term) {
+               if ($term == '')
+                       return new OracleSearchResultSet(false, '');
+               
                $resultSet = $this->db->resultObject($this->db->query($this->getQuery($this->filter($term), false)));
                return new MySQLSearchResultSet($resultSet, $this->searchTerms);
        }
@@ -214,6 +220,7 @@ class SearchOracle extends SearchEngine {
  * @ingroup Search
  */
 class OracleSearchResultSet extends SearchResultSet {
+
        function __construct($resultSet, $terms) {
                $this->mResultSet = $resultSet;
                $this->mTerms = $terms;
@@ -224,10 +231,16 @@ class OracleSearchResultSet extends SearchResultSet {
        }
 
        function numRows() {
-               return $this->mResultSet->numRows();
+               if ($this->mResultSet === false )
+                       return 0;
+               else
+                       return $this->mResultSet->numRows();
        }
 
        function next() {
+               if ($this->mResultSet === false )
+                       return false;
+
                $row = $this->mResultSet->fetchObject();
                if ($row === false)
                        return false;
index 3014d8c..a0700db 100644 (file)
@@ -31,40 +31,46 @@ class ORAResult {
        private $cursor;
        private $stmt;
        private $nrows;
-       private $db;
 
-       function __construct(&$db, $stmt) {
+       private $unique;
+
+       function __construct(&$db, $stmt, $unique = false) {
                $this->db =& $db;
+
                if (($this->nrows = oci_fetch_all($stmt, $this->rows, 0, -1, OCI_FETCHSTATEMENT_BY_ROW | OCI_NUM)) === false) {
                        $e = oci_error($stmt);
                        $db->reportQueryError($e['message'], $e['code'], '', __FUNCTION__);
                        return;
                }
 
+               if ($unique) {
+                       $this->rows = array_unique($this->rows);
+                       $this->nrows = count($this->rows);
+               }
+
                $this->cursor = 0;
                $this->stmt = $stmt;
        }
 
-       function free() {
+       public function free() {
                oci_free_statement($this->stmt);
        }
 
-       function seek($row) {
+       public function seek($row) {
                $this->cursor = min($row, $this->nrows);
        }
 
-       function numRows() {
+       public function numRows() {
                return $this->nrows;
        }
 
-       function numFields() {
+       public function numFields() {
                return oci_num_fields($this->stmt);
        }
 
-       function fetchObject() {
+       public function fetchObject() {
                if ($this->cursor >= $this->nrows)
                        return false;
-
                $row = $this->rows[$this->cursor++];
                $ret = new stdClass();
                foreach ($row as $k => $v) {
@@ -75,7 +81,7 @@ class ORAResult {
                return $ret;
        }
 
-       function fetchAssoc() {
+       public function fetchRow() {
                if ($this->cursor >= $this->nrows)
                        return false;
 
@@ -90,6 +96,60 @@ class ORAResult {
        }
 }
 
+/**
+ * Utility class.
+ * @ingroup Database
+ */
+class ORAField {
+       private $name, $tablename, $default, $max_length, $nullable,
+               $is_pk, $is_unique, $is_multiple, $is_key, $type;
+
+       function __construct($info) {
+               $this->name = $info['column_name'];
+               $this->tablename = $info['table_name'];
+               $this->default = $info['data_default'];
+               $this->max_length = $info['data_length'];
+               $this->nullable = $info['not_null'];
+               $this->is_pk = isset($info['prim']) && $info['prim'] == 1 ? 1 : 0;
+               $this->is_unique = isset($info['uniq']) && $info['uniq'] == 1 ? 1 : 0;
+               $this->is_multiple = isset($info['nonuniq']) && $info['nonuniq'] == 1 ? 1 : 0;
+               $this->is_key = ($this->is_pk || $this->is_unique || $this->is_multiple);
+               $this->type = $info['data_type'];
+       }
+       function name() {
+               return $this->name;
+       }
+
+       function tableName() {
+               return $this->tablename;
+       }
+
+       function defaultValue() {
+               return $this->default;
+       }
+
+       function maxLength() {
+               return $this->max_length;
+       }
+
+       function nullable() {
+               return $this->nullable;
+       }
+       
+       function isKey() {
+               return $this->is_key;
+       }
+
+       function isMultipleKey() {
+               return $this->is_multiple;
+       }
+
+       function type() {
+               return $this->type;
+       }
+}
+
 /**
  * @ingroup Database
  */
@@ -101,20 +161,14 @@ class DatabaseOracle extends Database {
        var $cursor = 0;
        var $mAffectedRows;
 
+       var $ignore_DUP_VAL_ON_INDEX = false;
+
        function DatabaseOracle($server = false, $user = false, $password = false, $dbName = false,
-               $failFunction = false, $flags = 0 )
+               $failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
        {
-
-               global $wgOut;
-               # Can't get a reference if it hasn't been set yet
-               if ( !isset( $wgOut ) ) {
-                       $wgOut = NULL;
-               }
-               $this->mOut =& $wgOut;
-               $this->mFailFunction = $failFunction;
-               $this->mFlags = $flags;
-               $this->open( $server, $user, $password, $dbName);
-
+               $tablePrefix = $tablePrefix == 'get from global' ? $tablePrefix : strtoupper($tablePrefix);
+               parent::__construct($server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix);
+               wfRunHooks( 'DatabaseOraclePostInit', array(&$this));
        }
 
        function cascadingDeletes() {
@@ -153,8 +207,7 @@ class DatabaseOracle extends Database {
                if ( !function_exists( 'oci_connect' ) ) {
                        throw new DBConnectionError( $this, "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n (Note: if you recently installed PHP, you may need to restart your webserver and database)\n" );
                }
-
-               # Needed for proper UTF-8 functionality
+               
                putenv("NLS_LANG=AMERICAN_AMERICA.AL32UTF8");
 
                $this->close();
@@ -167,8 +220,11 @@ class DatabaseOracle extends Database {
                        return;
                }
 
-               error_reporting( E_ALL );
-               $this->mConn = oci_connect($user, $password, $dbName);
+               //error_reporting( E_ALL ); //whoever had this bright idea
+               if ( $this->mFlags & DBO_DEFAULT )
+                       $this->mConn = oci_new_connect($user, $password, $dbName);
+               else
+                       $this->mConn = oci_connect($user, $password, $dbName);
 
                if ($this->mConn == false) {
                        wfDebug("DB connection error\n");
@@ -178,6 +234,11 @@ class DatabaseOracle extends Database {
                }
 
                $this->mOpened = true;
+               
+               #removed putenv calls because they interfere with the system globaly
+               $this->doQuery('ALTER SESSION SET NLS_TIMESTAMP_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'');
+               $this->doQuery('ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'');
+               
                return $this->mConn;
        }
 
@@ -204,18 +265,36 @@ class DatabaseOracle extends Database {
                        throw new MWException("SQL encoding is invalid");
                }
 
+               //handle some oracle specifics
+               //remove AS column/table/subquery namings
+               $sql = preg_replace('/ as /i', ' ', $sql);
+               // Oracle has issues with UNION clause if the statement includes LOB fields
+               // So we do a UNION ALL and then filter the results array with array_unique
+               $union_unique = (preg_match('/\/\* UNION_UNIQUE \*\/ /', $sql) != 0);
+               //EXPLAIN syntax in Oracle is EXPLAIN PLAN FOR and it return nothing
+               //you have to select data from plan table after explain
+               $explain_id = date('dmYHis');
+               $sql = preg_replace('/^EXPLAIN /', 'EXPLAIN PLAN SET STATEMENT_ID = \''.$explain_id.'\' FOR', $sql, 1, $explain_count);
+                       
+               
                if (($this->mLastResult = $stmt = oci_parse($this->mConn, $sql)) === false) {
                        $e = oci_error($this->mConn);
                        $this->reportQueryError($e['message'], $e['code'], $sql, __FUNCTION__);
                }
 
+               $olderr = error_reporting(E_ERROR);
                if (oci_execute($stmt, $this->execFlags()) == false) {
                        $e = oci_error($stmt);
-                       $this->reportQueryError($e['message'], $e['code'], $sql, __FUNCTION__);
+                       if (!$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1')
+                               $this->reportQueryError($e['message'], $e['code'], $sql, __FUNCTION__);
                }
-               if (oci_statement_type($stmt) == "SELECT")
-                       return new ORAResult($this, $stmt);
-               else {
+               error_reporting($olderr);
+
+               if ($explain_count > 0) {
+                       return $this->doQuery('SELECT id, cardinality "ROWS" FROM plan_table WHERE statement_id = \''.$explain_id.'\'');
+               } elseif (oci_statement_type($stmt) == "SELECT") {
+                       return new ORAResult($this, $stmt, $union_unique);
+               } else {
                        $this->mAffectedRows = oci_num_rows($stmt);
                        return true;
                }
@@ -226,27 +305,47 @@ class DatabaseOracle extends Database {
        }
 
        function freeResult($res) {
-               $res->free();
+               if ( $res instanceof ORAResult ) {
+                       $res->free();
+               } else {
+                       $res->result->free();
+               }
        }
 
        function fetchObject($res) {
-               return $res->fetchObject();
+               if ( $res instanceof ORAResult ) {
+                       return $res->numRows();
+               } else {
+                       return $res->result->fetchObject();
+               }
        }
 
        function fetchRow($res) {
-               return $res->fetchAssoc();
+               if ( $res instanceof ORAResult ) {
+                       return $res->fetchRow();
+               } else {
+                       return $res->result->fetchRow();
+               }
        }
 
        function numRows($res) {
-               return $res->numRows();
+               if ( $res instanceof ORAResult ) {
+                       return $res->numRows();
+               } else {
+                       return $res->result->numRows();
+               }
        }
 
        function numFields($res) {
-               return $res->numFields();
+               if ( $res instanceof ORAResult ) {
+                       return $res->numFields();
+               } else {
+                       return $res->result->numFields();
+               }
        }
 
        function fieldName($stmt, $n) {
-               return pg_field_name($stmt, $n);
+               return oci_field_name($stmt, $n);
        }
 
        /**
@@ -257,7 +356,11 @@ class DatabaseOracle extends Database {
        }
 
        function dataSeek($res, $row) {
-               $res->seek($row);
+               if ( $res instanceof ORAResult ) {
+                       $res->seek($row);
+               } else {
+                       $res->result->seek($row);
+               }
        }
 
        function lastError() {
@@ -284,63 +387,56 @@ class DatabaseOracle extends Database {
         * Returns information about an index
         * If errors are explicitly ignored, returns NULL on failure
         */
-       function indexInfo( $table, $index, $fname = 'Database::indexExists' ) {
+       function indexInfo( $table, $index, $fname = 'DatabaseOracle::indexExists' ) {
                return false;
        }
 
-       function indexUnique ($table, $index, $fname = 'Database::indexUnique' ) {
+       function indexUnique ($table, $index, $fname = 'DatabaseOracle::indexUnique' ) {
                return false;
        }
 
-       function insert( $table, $a, $fname = 'Database::insert', $options = array() ) {
+       function insert( $table, $a, $fname = 'DatabaseOracle::insert', $options = array() ) {
+               if ( !count( $a ) )
+                       return true;
+
                if (!is_array($options))
                        $options = array($options);
 
-               #if (in_array('IGNORE', $options))
-               #       $oldIgnore = $this->ignoreErrors(true);
+    if (in_array('IGNORE', $options))
+                       $this->ignore_DUP_VAL_ON_INDEX = true;
 
-               # IGNORE is performed using single-row inserts, ignoring errors in each
-               # FIXME: need some way to distiguish between key collision and other types of error
-               //$oldIgnore = $this->ignoreErrors(true);
                if (!is_array(reset($a))) {
                        $a = array($a);
                }
                foreach ($a as $row) {
                        $this->insertOneRow($table, $row, $fname);
                }
-               //$this->ignoreErrors($oldIgnore);
                $retVal = true;
 
-               //if (in_array('IGNORE', $options))
-               //      $this->ignoreErrors($oldIgnore);
+               if (in_array('IGNORE', $options))
+                       $this->ignore_DUP_VAL_ON_INDEX = false;
 
                return $retVal;
        }
 
        function insertOneRow($table, $row, $fname) {
+               global $wgLang;
+
                // "INSERT INTO tables (a, b, c)"
                $sql = "INSERT INTO " . $this->tableName($table) . " (" . join(',', array_keys($row)) . ')';
                $sql .= " VALUES (";
 
                // for each value, append ":key"
                $first = true;
-               $returning = '';
                foreach ($row as $col => $val) {
-                       if (is_object($val)) {
-                               $what = "EMPTY_BLOB()";
-                               assert($returning === '');
-                               $returning = " RETURNING $col INTO :bval";
-                               $blobcol = $col;
-                       } else
-                               $what = ":$col";
-
                        if ($first)
-                               $sql .= "$what";
+                               $sql .= ':'.$col;
                        else
-                               $sql.= ", $what";
+                               $sql.= ', :'.$col;
+                       
                        $first = false;
                }
-               $sql .= ") $returning";
+               $sql .= ')';
 
                $stmt = oci_parse($this->mConn, $sql);
                foreach ($row as $col => $val) {
@@ -349,39 +445,136 @@ class DatabaseOracle extends Database {
                                        $this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
                        }
                }
-
-               if (($bval = oci_new_descriptor($this->mConn, OCI_D_LOB)) === false) {
-                       $e = oci_error($stmt);
-                       throw new DBUnexpectedError($this, "Cannot create LOB descriptor: " . $e['message']);
+               
+               $stmt = oci_parse($this->mConn, $sql);
+               foreach ($row as $col => $val) {
+                       $col_type=$this->fieldInfo($this->tableName($table), $col)->type();
+                       if ($col_type != 'BLOB' && $col_type != 'CLOB') {
+                               if (is_object($val))
+                                       $val = $val->getData();
+                               
+                               if (preg_match('/^timestamp.*/i', $col_type) == 1 && strtolower($val) == 'infinity') 
+                                       $val = '31-12-2030 12:00:00.000000';
+                               
+                               if (oci_bind_by_name($stmt, ":$col", $wgLang->checkTitleEncoding($val)) === false)
+                                       $this->reportQueryError($this->lastErrno(), $this->lastError(), $sql, __METHOD__);
+                       } else {
+                               if (($lob[$col] = oci_new_descriptor($this->mConn, OCI_D_LOB)) === false) {
+                                       $e = oci_error($stmt);
+                                       throw new DBUnexpectedError($this, "Cannot create LOB descriptor: " . $e['message']);
+                               }
+                                       
+                               if (is_object($val)) {
+                                       $lob[$col]->writeTemporary($val->getData());
+                                       oci_bind_by_name($stmt, ":$col", $lob[$col], -1, SQLT_BLOB);
+                               } else {
+                                       $lob[$col]->writeTemporary($val);
+                                       oci_bind_by_name($stmt, ":$col", $lob[$col], -1, OCI_B_CLOB);
+                               }
+                       }
                }
-
-               if (strlen($returning))
-                       oci_bind_by_name($stmt, ":bval", $bval, -1, SQLT_BLOB);
-
+               
+               $olderr = error_reporting(E_ERROR);
                if (oci_execute($stmt, OCI_DEFAULT) === false) {
                        $e = oci_error($stmt);
-                       $this->reportQueryError($e['message'], $e['code'], $sql, __METHOD__);
-               }
-               if (strlen($returning)) {
-                       $bval->save($row[$blobcol]->getData());
-                       $bval->free();
+                       
+                       if (!$this->ignore_DUP_VAL_ON_INDEX || $e['code'] != '1')
+                               $this->reportQueryError($e['message'], $e['code'], $sql, __METHOD__);
+                       else
+                               $this->mAffectedRows = oci_num_rows($stmt);
+               } else 
+                       $this->mAffectedRows = oci_num_rows($stmt);
+               error_reporting($olderr);
+               
+               if (isset($lob)){
+                       foreach ($lob as $lob_i => $lob_v) {
+                               $lob_v->free();
+                       }
                }
+               
                if (!$this->mTrxLevel)
                        oci_commit($this->mConn);
-
+               
                oci_free_statement($stmt);
        }
 
+       function insertSelect( $destTable, $srcTable, $varMap, $conds, $fname = 'DatabaseOracle::insertSelect',
+               $insertOptions = array(), $selectOptions = array() )
+       {
+               $destTable = $this->tableName( $destTable );
+               if( !is_array( $selectOptions ) ) {
+                       $selectOptions = array( $selectOptions );
+               }
+               list( $startOpts, $useIndex, $tailOpts ) = $this->makeSelectOptions( $selectOptions );
+               if( is_array( $srcTable ) ) {
+                       $srcTable =  implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) );
+               } else {
+                       $srcTable = $this->tableName( $srcTable );
+               }
+               $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
+                       " SELECT $startOpts " . implode( ',', $varMap ) .
+                       " FROM $srcTable $useIndex ";
+               if ( $conds != '*' ) {
+                       $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
+               }
+               $sql .= " $tailOpts";
+
+               if (in_array('IGNORE', $insertOptions)) 
+                       $this->ignore_DUP_VAL_ON_INDEX = true;
+
+               $retval = $this->query( $sql, $fname );
+
+               if (in_array('IGNORE', $insertOptions))
+                       $this->ignore_DUP_VAL_ON_INDEX = false;
+               
+               return $retval;
+       }
+
        function tableName( $name ) {
-               # Replace reserved words with better ones
+               global $wgSharedDB, $wgSharedPrefix, $wgSharedTables;
+               /*
+               Replace reserved words with better ones
+               Useing uppercase, because that's the only way oracle can handle 
+               quoted tablenames
+               */
                switch( $name ) {
                        case 'user':
-                               return 'mwuser';
+                               $name = 'MWUSER'; break;
                        case 'text':
-                               return 'pagecontent';
-                       default:
-                               return $name;
+                               $name = 'PAGECONTENT'; break;
                }
+
+               /*
+                       The rest of procedure is equal to generic Databse class
+                       except for the quoting style
+               */
+               if ( $name[0] == '"' && substr( $name, -1, 1 ) == '"' ) return $name;
+
+               if( preg_match( '/(^|\s)(DISTINCT|JOIN|ON|AS)(\s|$)/i', $name ) !== 0 ) return $name;
+               $dbDetails = array_reverse( explode( '.', $name, 2 ) );
+               if( isset( $dbDetails[1] ) ) @list( $table, $database ) = $dbDetails;
+               else                         @list( $table ) = $dbDetails;
+               
+               $prefix = $this->mTablePrefix;
+               
+               if( isset($database) ) $table = ( $table[0] == '`' ? $table : "`{$table}`" );
+               
+               if( !isset( $database ) 
+                && isset( $wgSharedDB )
+                && $table[0] != '"'
+                && isset( $wgSharedTables )
+                && is_array( $wgSharedTables )
+                && in_array( $table, $wgSharedTables ) ) {
+                       $database = $wgSharedDB;
+                       $prefix   = isset( $wgSharedPrefix ) ? $wgSharedPrefix : $prefix;
+               }
+               
+               if( isset($database) ) $database = ( $database[0] == '"' ? $database : "\"{$database}\"" );
+               $table = ( $table[0] == '"' ? $table : "\"{$prefix}{$table}\"" );
+               
+               $tableName = ( isset($database) ? "{$database}.{$table}" : "{$table}" );
+               
+               return strtoupper($tableName);
        }
 
        /**
@@ -411,7 +604,7 @@ class DatabaseOracle extends Database {
        # It may be more efficient to leave off unique indexes which are unlikely to collide.
        # However if you do this, you run the risk of encountering errors which wouldn't have
        # occurred in MySQL
-       function replace( $table, $uniqueIndexes, $rows, $fname = 'Database::replace' ) {
+       function replace( $table, $uniqueIndexes, $rows, $fname = 'DatabaseOracle::replace' ) {
                $table = $this->tableName($table);
 
                if (count($rows)==0) {
@@ -454,16 +647,14 @@ class DatabaseOracle extends Database {
                        }
 
                        # Now insert the row
-                       $sql = "INSERT INTO $table (" . $this->makeList( array_keys( $row ), LIST_NAMES ) .') VALUES (' .
-                               $this->makeList( $row, LIST_COMMA ) . ')';
-                       $this->query($sql, $fname);
+                       $this->insert( $table, $row, $fname );
                }
        }
 
        # DELETE where the condition is a join
-       function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = "Database::deleteJoin" ) {
+       function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = "DatabaseOracle::deleteJoin" ) {
                if ( !$conds ) {
-                       throw new DBUnexpectedError($this,  'Database::deleteJoin() called with empty $conds' );
+                       throw new DBUnexpectedError($this,  'DatabaseOracle::deleteJoin() called with empty $conds' );
                }
 
                $delTable = $this->tableName( $delTable );
@@ -502,7 +693,13 @@ class DatabaseOracle extends Database {
        function limitResult($sql, $limit, $offset) {
                if ($offset === false)
                        $offset = 0;
-               return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < 1 + $limit + $offset";
+               return "SELECT * FROM ($sql) WHERE rownum >= (1 + $offset) AND rownum < (1 + $limit + $offset)";
+       }
+
+
+       function unionQueries($sqls, $all = false) {
+               $glue = ' UNION ALL ';
+               return 'SELECT * '.($all?'':'/* UNION_UNIQUE */ ').'FROM ('.implode( $glue, $sqls ).')' ;
        }
 
        /**
@@ -540,12 +737,12 @@ class DatabaseOracle extends Database {
                ++$this->mErrorCount;
 
                if ($ignore || $tempIgnore) {
-echo "error ignored! query = [$sql]\n";
+//echo "error ignored! query = [$sql]\n";
                        wfDebug("SQL ERROR (ignored): $error\n");
                        $this->ignoreErrors( $ignore );
                }
                else {
-echo "error!\n";
+//echo "error!\n";
                        $message = "A database error has occurred\n" .
                                "Query: $sql\n" .
                                "Function: $fname\n" .
@@ -572,24 +769,51 @@ echo "error!\n";
         * Query whether a given table exists (in the given schema, or the default mw one if not given)
         */
        function tableExists($table) {
-               $etable= $this->addQuotes($table);
-               $SQL = "SELECT 1 FROM user_tables WHERE table_name='$etable'";
-               $res = $this->query($SQL);
-               $count = $res ? oci_num_rows($res) : 0;
-               if ($res)
-                       $this->freeResult($res);
+               $SQL = "SELECT 1 FROM user_tables WHERE table_name='$table'";
+               $res = $this->doQuery($SQL);
+               if ($res) {
+                       $count = $res->numRows();
+                       $res->free();
+               } else {
+                       $count = 0;
+               }
                return $count;
        }
 
        /**
         * Query whether a given column exists in the mediawiki schema
+        * based on prebuilt table to simulate MySQL field info and keep query speed minimal
         */
        function fieldExists( $table, $field ) {
-               return true; // XXX
+               if (!isset($this->fieldInfo_stmt))
+                       $this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
+
+               oci_bind_by_name($this->fieldInfo_stmt, ':tab', trim($table, '"'));
+               oci_bind_by_name($this->fieldInfo_stmt, ':col', $field);
+
+               if (oci_execute($this->fieldInfo_stmt, OCI_DEFAULT) === false) {
+                       $e = oci_error($this->fieldInfo_stmt);
+                       $this->reportQueryError($e['message'], $e['code'], 'fieldInfo QUERY', __METHOD__);
+                       return false;
+               }
+               $res = new ORAResult($this,$this->fieldInfo_stmt);
+               return $res->numRows() != 0;
        }
 
        function fieldInfo( $table, $field ) {
-               return false; // XXX
+               if (!isset($this->fieldInfo_stmt))
+                       $this->fieldInfo_stmt = oci_parse($this->mConn, 'SELECT * FROM wiki_field_info_full WHERE table_name = upper(:tab) and column_name = UPPER(:col)');
+
+               oci_bind_by_name($this->fieldInfo_stmt, ':tab', trim($table, '"'));
+               oci_bind_by_name($this->fieldInfo_stmt, ':col', $field);
+
+               if (oci_execute($this->fieldInfo_stmt, OCI_DEFAULT) === false) {
+                       $e = oci_error($this->fieldInfo_stmt);
+                       $this->reportQueryError($e['message'], $e['code'], 'fieldInfo QUERY', __METHOD__);
+                       return false;
+               }
+               $res = new ORAResult($this,$this->fieldInfo_stmt);
+               return new ORAField($res->fetchRow());
        }
 
        function begin( $fname = '' ) {
@@ -620,8 +844,9 @@ echo "error!\n";
        }
 
        function addQuotes( $s ) {
-       global  $wgLang;
-               $s = $wgLang->checkTitleEncoding($s);
+               global $wgLang;
+               if (isset($wgLang->mLoaded) && $wgLang->mLoaded)
+                       $s = $wgLang->checkTitleEncoding($s);
                return "'" . $this->strencode($s) . "'";
        }
 
@@ -634,6 +859,15 @@ echo "error!\n";
                return true;
        }
 
+       function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) {
+               if (is_array($table)) 
+                       foreach ($table as $tab)
+                               $tab = $this->tableName($tab);
+               else
+                       $table = $this->tableName($table);
+               return parent::selectRow($table, $vars, $conds, $fname, $options, $join_conds);
+       }
+
        /**
         * Returns an optional USE INDEX clause to go after the table, and a
         * string to go at the end of the query
@@ -658,12 +892,6 @@ echo "error!\n";
                if ( isset( $options['GROUP BY'] ) ) $preLimitTail .= " GROUP BY {$options['GROUP BY']}";
                if ( isset( $options['ORDER BY'] ) ) $preLimitTail .= " ORDER BY {$options['ORDER BY']}";
 
-               if (isset($options['LIMIT'])) {
-               //      $tailOpts .= $this->limitResult('', $options['LIMIT'],
-               //              isset($options['OFFSET']) ? $options['OFFSET']
-               //              : false);
-               }
-
                #if ( isset( $noKeyOptions['FOR UPDATE'] ) ) $tailOpts .= ' FOR UPDATE';
                #if ( isset( $noKeyOptions['LOCK IN SHARE MODE'] ) ) $tailOpts .= ' LOCK IN SHARE MODE';
                if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) $startOpts .= 'DISTINCT';
@@ -677,6 +905,38 @@ echo "error!\n";
                return array( $startOpts, $useIndex, $preLimitTail, $postLimitTail );
        }
 
+       public function makeList( $a, $mode = LIST_COMMA ) {
+               if ( !is_array( $a ) ) {
+                       throw new DBUnexpectedError( $this, 'DatabaseOracle::makeList called with incorrect parameters' );
+               }
+               $a2 = array();
+               foreach ($a as $key => $value) {
+                       if (strpos($key, ' & ') !== FALSE)
+                               $a2[preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $key)] = $value;
+                       elseif (strpos($key, ' | ') !== FALSE)
+                               $a2[preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $key)] = $value;
+                       elseif (!is_array($value)) {
+                               if (strpos($value, ' = ') !== FALSE) {
+                                       if (strpos($value, ' & ') !== FALSE)
+                                               $a2[$key] = preg_replace('/(.*)\s&\s(.*?)\s=\s(.*)/', 'BITAND($1, $2) = $3', $value);
+                                       elseif (strpos($value, ' | ') !== FALSE)
+                                               $a2[$key] = preg_replace('/(.*)\s|\s(.*?)\s=\s(.*)/', 'BITOR($1, $2) = $3', $value);
+                                       else $a2[$key] = $value;
+                               } 
+                               elseif (strpos($value, ' & ') !== FALSE)
+                                       $a2[$key] = preg_replace('/(.*)\s&\s(.*)/', 'BITAND($1, $2)', $value);
+                               elseif (strpos($value, ' | ') !== FALSE)
+                                       $a2[$key] = preg_replace('/(.*)\s|\s(.*)/', 'BITOR($1, $2)', $value);
+                               else
+                                       $a2[$key] = $value;
+                       }
+                       else
+                               $a2[$key] = $value;
+               }
+
+               return parent::makeList($a2, $mode);
+       }
+
        public function setTimeout( $timeout ) {
                // @todo fixme no-op
        }
index 6ebd570..18556c2 100644 (file)
@@ -25,8 +25,18 @@ class AncientPagesPage extends QueryPage {
                $db = wfGetDB( DB_SLAVE );
                $page = $db->tableName( 'page' );
                $revision = $db->tableName( 'revision' );
-               $epoch = $wgDBtype == 'mysql' ? 'UNIX_TIMESTAMP(rev_timestamp)' :
-                       'EXTRACT(epoch FROM rev_timestamp)';
+
+               switch ($wgDBtype) {
+                       case 'mysql': 
+                               $epoch = 'UNIX_TIMESTAMP(rev_timestamp)'; 
+                               break;
+                       case 'oracle': 
+                               $epoch = '((trunc(rev_timestamp) - to_date(\'19700101\',\'YYYYMMDD\')) * 86400)'; 
+                               break;
+                       default:
+                               $epoch = 'EXTRACT(epoch FROM rev_timestamp)';
+               }
+
                return
                        "SELECT 'Ancientpages' as type,
                                        page_namespace as namespace,
index fa66555..778bb03 100644 (file)
@@ -25,9 +25,16 @@ class UnusedimagesPage extends ImageQueryPage {
                global $wgCountCategorizedImagesAsUsed, $wgDBtype;
                $dbr = wfGetDB( DB_SLAVE );
 
-               $epoch = $wgDBtype == 'mysql' ?
-                       'UNIX_TIMESTAMP(img_timestamp)' :
-                       'EXTRACT(epoch FROM img_timestamp)';
+               switch ($wgDBtype) {
+                       case 'mysql': 
+                               $epoch = 'UNIX_TIMESTAMP(img_timestamp)'; 
+                               break;
+                       case 'oracle': 
+                               $epoch = '((trunc(img_timestamp) - to_date(\'19700101\',\'YYYYMMDD\')) * 86400)'; 
+                               break;
+                       default:
+                               $epoch = 'EXTRACT(epoch FROM img_timestamp)';
+               }
 
                if ( $wgCountCategorizedImagesAsUsed ) {
                        list( $page, $image, $imagelinks, $categorylinks ) = $dbr->tableNamesN( 'page', 'image', 'imagelinks', 'categorylinks' );
index 6d4b8ed..61211fb 100644 (file)
--- SQL to create the initial tables for the MediaWiki database.
--- This is read and executed by the install script; you should
--- not have to run it by itself unless doing a manual install.
--- This is the Oracle version (based on PostgreSQL schema).
--- For information about each table, please see the notes in maintenance/tables.sql
+DEFINE mw_prefix='';
 
-CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0;
 
-CREATE TABLE mwuser ( -- replace reserved word 'user'
-  user_id                   INTEGER  NOT NULL  PRIMARY KEY,
-  user_name                 VARCHAR(255)     NOT NULL  UNIQUE,
-  user_real_name            CLOB,
-  user_password             CLOB,
-  user_newpassword          CLOB,
-  user_newpass_time         TIMESTAMP WITH TIME ZONE,
-  user_token                CHAR(32),
-  user_email                CLOB,
-  user_email_token          CHAR(32),
-  user_email_token_expires  TIMESTAMP WITH TIME ZONE,
-  user_email_authenticated  TIMESTAMP WITH TIME ZONE,
+CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0;
+CREATE TABLE &mw_prefix.mwuser ( -- replace reserved word 'user'
+  user_id                   NUMBER  NOT NULL,
+  user_name                 VARCHAR2(255)     NOT NULL,
+  user_real_name            VARCHAR2(512),
+  user_password             VARCHAR2(255),
+  user_newpassword          VARCHAR2(255),
+  user_newpass_time         TIMESTAMP(6) WITH TIME ZONE,
+  user_token                VARCHAR2(32),
+  user_email                VARCHAR2(255),
+  user_email_token          VARCHAR2(32),
+  user_email_token_expires  TIMESTAMP(6) WITH TIME ZONE,
+  user_email_authenticated  TIMESTAMP(6) WITH TIME ZONE,
   user_options              CLOB,
-  user_touched              TIMESTAMP WITH TIME ZONE,
-  user_registration         TIMESTAMP WITH TIME ZONE,
-  user_editcount            INTEGER
+  user_touched              TIMESTAMP(6) WITH TIME ZONE,
+  user_registration         TIMESTAMP(6) WITH TIME ZONE,
+  user_editcount            NUMBER
 );
-CREATE INDEX user_email_token_idx ON mwuser (user_email_token);
+ALTER TABLE &mw_prefix.mwuser ADD CONSTRAINT &mw_prefix.mwuser_pk PRIMARY KEY (user_id);
+CREATE UNIQUE INDEX &mw_prefix.mwuser_u01 ON &mw_prefix.mwuser (user_name);
+CREATE INDEX &mw_prefix.mwuser_i01 ON &mw_prefix.mwuser (user_email_token);
 
 -- Create a dummy user to satisfy fk contraints especially with revisions
-INSERT INTO mwuser
+INSERT INTO &mw_prefix.mwuser
   VALUES (user_user_id_seq.nextval,'Anonymous','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, '', current_timestamp, current_timestamp, 0);
 
-CREATE TABLE user_groups (
-  ug_user   INTEGER      NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE,
-  ug_group  CHAR(16)     NOT NULL
+CREATE TABLE &mw_prefix.user_groups (
+  ug_user   NUMBER      NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE,
+  ug_group  VARCHAR2(16)     NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.user_groups_u01 ON &mw_prefix.user_groups (ug_user,ug_group);
+CREATE INDEX &mw_prefix.user_groups_i01 ON &mw_prefix.user_groups (ug_group);
+
+CREATE TABLE &mw_prefix.user_newtalk (
+  user_id  NUMBER NOT NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE,
+  user_ip  VARCHAR2(40)        NULL,
+  user_last_timestamp         TIMESTAMP(6) WITH TIME ZONE
 );
-CREATE UNIQUE INDEX user_groups_unique ON user_groups (ug_user, ug_group);
+CREATE INDEX &mw_prefix.user_newtalk_i01 ON &mw_prefix.user_newtalk (user_id);
+CREATE INDEX &mw_prefix.user_newtalk_i02 ON &mw_prefix.user_newtalk (user_ip);
 
-CREATE TABLE user_newtalk (
-  user_id  INTEGER NOT NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE,
-  user_ip  VARCHAR(40)        NULL
+CREATE TABLE &mw_prefix.user_properties (
+  up_user NUMBER NOT NULL,
+  up_property VARCHAR2(32) NOT NULL,
+  up_value BLOB
 );
-CREATE INDEX user_newtalk_id_idx ON user_newtalk (user_id);
-CREATE INDEX user_newtalk_ip_idx ON user_newtalk (user_ip);
+CREATE UNIQUE INDEX &mw_prefix.user_properties_u01 on &mw_prefix.user_properties (up_user,up_property);
+CREATE INDEX &mw_prefix.user_properties_i01 on &mw_prefix.user_properties (up_property);
+
 
 CREATE SEQUENCE page_page_id_seq;
-CREATE TABLE page (
-  page_id            INTEGER        NOT NULL PRIMARY KEY,
-  page_namespace     SMALLINT       NOT NULL,
-  page_title         VARCHAR(255)           NOT NULL,
-  page_restrictions  CLOB,
-  page_counter       INTEGER         DEFAULT 0 NOT NULL,
-  page_is_redirect   CHAR           DEFAULT 0 NOT NULL,
-  page_is_new        CHAR           DEFAULT 0 NOT NULL,
-  page_random        NUMERIC(15,14) NOT NULL,
-  page_touched       TIMESTAMP WITH TIME ZONE,
-  page_latest        INTEGER        NOT NULL, -- FK?
-  page_len           INTEGER        NOT NULL
-);
-CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title);
-CREATE INDEX page_random_idx         ON page (page_random);
-CREATE INDEX page_len_idx            ON page (page_len);
-
-CREATE TRIGGER page_set_random BEFORE INSERT ON page
+CREATE TABLE &mw_prefix.page (
+  page_id            NUMBER        NOT NULL,
+  page_namespace     NUMBER       NOT NULL,
+  page_title         VARCHAR2(255)           NOT NULL,
+  page_restrictions  VARCHAR2(255),
+  page_counter       NUMBER         DEFAULT 0 NOT NULL,
+  page_is_redirect   CHAR(1)           DEFAULT 0 NOT NULL,
+  page_is_new        CHAR(1)           DEFAULT 0 NOT NULL,
+  page_random        NUMBER(15,14) NOT NULL,
+  page_touched       TIMESTAMP(6) WITH TIME ZONE,
+  page_latest        NUMBER        NOT NULL, -- FK?
+  page_len           NUMBER        NOT NULL
+);
+ALTER TABLE &mw_prefix.page ADD CONSTRAINT &mw_prefix.page_pk PRIMARY KEY (page_id);
+CREATE UNIQUE INDEX &mw_prefix.page_u01 ON &mw_prefix.page (page_namespace,page_title);
+CREATE INDEX &mw_prefix.page_i01 ON &mw_prefix.page (page_random);
+CREATE INDEX &mw_prefix.page_i02 ON &mw_prefix.page (page_len);
+
+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;
+                SELECT dbms_random.value INTO :NEW.page_random FROM dual;
         END;
 /
 
 CREATE SEQUENCE rev_rev_id_val;
-CREATE TABLE revision (
-  rev_id          INTEGER      NOT NULL PRIMARY KEY,
-  rev_page        INTEGER          NULL  REFERENCES page (page_id) ON DELETE CASCADE,
-  rev_text_id     INTEGER          NULL, -- FK
-  rev_comment     CLOB,
-  rev_user        INTEGER      NOT NULL  REFERENCES mwuser(user_id),
-  rev_user_text   VARCHAR(255)         NOT NULL,
-  rev_timestamp   TIMESTAMP WITH TIME ZONE  NOT NULL,
-  rev_minor_edit  CHAR         DEFAULT '0' NOT NULL,
-  rev_deleted     CHAR         DEFAULT '0' NOT NULL,
-  rev_len         INTEGER          NULL,
-  rev_parent_id   INTEGER                 DEFAULT NULL
-);
-CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id);
-CREATE INDEX rev_text_id_idx        ON revision (rev_text_id);
-CREATE INDEX rev_timestamp_idx      ON revision (rev_timestamp);
-CREATE INDEX rev_user_idx           ON revision (rev_user);
-CREATE INDEX rev_user_text_idx      ON revision (rev_user_text);
-
+CREATE TABLE &mw_prefix.revision (
+  rev_id          NUMBER      NOT NULL,
+  rev_page        NUMBER          NULL  REFERENCES &mw_prefix.page (page_id) ON DELETE CASCADE,
+  rev_text_id     NUMBER          NULL,
+  rev_comment     VARCHAR2(255),
+  rev_user        NUMBER      NOT NULL  REFERENCES &mw_prefix.mwuser(user_id),
+  rev_user_text   VARCHAR2(255)         NOT NULL,
+  rev_timestamp   TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  rev_minor_edit  CHAR(1)         DEFAULT '0' NOT NULL,
+  rev_deleted     CHAR(1)         DEFAULT '0' NOT NULL,
+  rev_len         NUMBER          NULL,
+  rev_parent_id   NUMBER          DEFAULT NULL
+);
+ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_pk PRIMARY KEY (rev_id);
+CREATE UNIQUE INDEX &mw_prefix.revision_u01 ON &mw_prefix.revision (rev_page, rev_id);
+CREATE INDEX &mw_prefix.revision_i01 ON &mw_prefix.revision (rev_timestamp);
+CREATE INDEX &mw_prefix.revision_i02 ON &mw_prefix.revision (rev_page,rev_timestamp);
+CREATE INDEX &mw_prefix.revision_i03 ON &mw_prefix.revision (rev_user,rev_timestamp);
+CREATE INDEX &mw_prefix.revision_i04 ON &mw_prefix.revision (rev_user_text,rev_timestamp);
 
 CREATE SEQUENCE text_old_id_val;
-CREATE TABLE pagecontent ( -- replaces reserved word 'text'
-  old_id     INTEGER  NOT NULL PRIMARY KEY,
+CREATE TABLE &mw_prefix.pagecontent ( -- replaces reserved word 'text'
+  old_id     NUMBER  NOT NULL,
   old_text   CLOB,
-  old_flags  CLOB
+  old_flags  VARCHAR2(255)
 );
+ALTER TABLE &mw_prefix.pagecontent ADD CONSTRAINT &mw_prefix.pagecontent_pk PRIMARY KEY (old_id);
 
-
-CREATE SEQUENCE pr_id_val;
-CREATE TABLE page_restrictions (
-  pr_id      INTEGER      NOT NULL UNIQUE,
-  pr_page    INTEGER          NULL  REFERENCES page (page_id) ON DELETE CASCADE,
-  pr_type    VARCHAR(255)         NOT NULL,
-  pr_level   VARCHAR(255)         NOT NULL,
-  pr_cascade SMALLINT     NOT NULL,
-  pr_user    INTEGER          NULL,
-  pr_expiry  TIMESTAMP WITH TIME ZONE      NULL
-);
-ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type);
-
-CREATE TABLE archive (
-  ar_namespace   SMALLINT     NOT NULL,
-  ar_title       VARCHAR(255)         NOT NULL,
+CREATE TABLE &mw_prefix.archive (
+  ar_namespace   NUMBER    NOT NULL,
+  ar_title       VARCHAR2(255)         NOT NULL,
   ar_text        CLOB,
-  ar_comment     CLOB,
-  ar_user        INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  ar_user_text   CLOB         NOT NULL,
-  ar_timestamp   TIMESTAMP WITH TIME ZONE  NOT NULL,
-  ar_minor_edit  CHAR         DEFAULT '0' NOT NULL,
-  ar_flags       CLOB,
-  ar_rev_id      INTEGER,
-  ar_text_id     INTEGER,
-  ar_deleted     INTEGER      DEFAULT '0' NOT NULL
-);
-CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp);
-
-CREATE TABLE redirect (
-  rd_from       INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  rd_namespace  SMALLINT NOT NULL,
-  rd_title      VARCHAR(255)     NOT NULL
-);
-CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from);
-
-
-CREATE TABLE pagelinks (
-  pl_from       INTEGER   NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  pl_namespace  SMALLINT  NOT NULL,
-  pl_title      VARCHAR(255)      NOT NULL
-);
-CREATE UNIQUE INDEX pagelink_unique ON pagelinks (pl_from,pl_namespace,pl_title);
-
-CREATE TABLE templatelinks (
-  tl_from       INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  tl_namespace  INTEGER     NOT NULL,
-  tl_title      VARCHAR(255)     NOT NULL
-);
-CREATE UNIQUE INDEX templatelinks_unique ON templatelinks (tl_namespace,tl_title,tl_from);
-
-CREATE TABLE imagelinks (
-  il_from  INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  il_to    VARCHAR(255)     NOT NULL
-);
-CREATE UNIQUE INDEX il_from ON imagelinks (il_to,il_from);
-
-CREATE TABLE categorylinks (
-  cl_from       INTEGER      NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  cl_to         VARCHAR(255)         NOT NULL,
-  cl_sortkey    VARCHAR(86),
-  cl_timestamp  TIMESTAMP WITH TIME ZONE  NOT NULL
-);
-CREATE UNIQUE INDEX cl_from ON categorylinks (cl_from, cl_to);
-CREATE INDEX cl_sortkey     ON categorylinks (cl_to, cl_sortkey);
-
-CREATE TABLE externallinks (
-  el_from   INTEGER  NOT NULL  REFERENCES page(page_id) ON DELETE CASCADE,
-  el_to     VARCHAR(2048) NOT NULL,
-  el_index  CLOB     NOT NULL
-);
--- XXX CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to);
--- XXX CREATE INDEX externallinks_index   ON externallinks (el_index);
-
-CREATE TABLE langlinks (
-  ll_from    INTEGER  NOT NULL  REFERENCES page (page_id) ON DELETE CASCADE,
-  ll_lang    VARCHAR(10),
-  ll_title   VARCHAR(255)
-);
-CREATE UNIQUE INDEX langlinks_unique ON langlinks (ll_from,ll_lang);
-CREATE INDEX langlinks_lang_title    ON langlinks (ll_lang,ll_title);
-
-
-CREATE TABLE site_stats (
-  ss_row_id         INTEGER  NOT NULL  UNIQUE,
-  ss_total_views    INTEGER            DEFAULT 0,
-  ss_total_edits    INTEGER            DEFAULT 0,
-  ss_good_articles  INTEGER            DEFAULT 0,
-  ss_total_pages    INTEGER            DEFAULT -1,
-  ss_users          INTEGER            DEFAULT -1,
-  ss_admins         INTEGER            DEFAULT -1,
-  ss_images         INTEGER            DEFAULT 0
+  ar_comment     VARCHAR2(255),
+  ar_user        NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  ar_user_text   VARCHAR2(255)         NOT NULL,
+  ar_timestamp   TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  ar_minor_edit  CHAR(1)         DEFAULT '0' NOT NULL,
+  ar_flags       VARCHAR2(255),
+  ar_rev_id      NUMBER,
+  ar_text_id     NUMBER,
+  ar_deleted     NUMBER      DEFAULT '0' NOT NULL
+);
+CREATE INDEX &mw_prefix.archive_i01 ON &mw_prefix.archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX &mw_prefix.archive_i02 ON &mw_prefix.archive (ar_user_text,ar_timestamp);
+
+
+CREATE TABLE &mw_prefix.pagelinks (
+  pl_from       NUMBER   NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  pl_namespace  NUMBER  NOT NULL,
+  pl_title      VARCHAR2(255)      NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.pagelinks_u01 ON &mw_prefix.pagelinks (pl_from,pl_namespace,pl_title);
+CREATE UNIQUE INDEX &mw_prefix.pagelinks_u02 ON &mw_prefix.pagelinks (pl_namespace,pl_title,pl_from);
+
+CREATE TABLE &mw_prefix.templatelinks (
+  tl_from       NUMBER  NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  tl_namespace  NUMBER     NOT NULL,
+  tl_title      VARCHAR2(255)     NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.templatelinks_u01 ON &mw_prefix.templatelinks (tl_from,tl_namespace,tl_title);
+CREATE UNIQUE INDEX &mw_prefix.templatelinks_u02 ON &mw_prefix.templatelinks (tl_namespace,tl_title,tl_from);
+
+CREATE TABLE &mw_prefix.imagelinks (
+  il_from  NUMBER  NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  il_to    VARCHAR2(255)     NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.imagelinks_u01 ON &mw_prefix.imagelinks (il_from,il_to);
+CREATE UNIQUE INDEX &mw_prefix.imagelinks_u02 ON &mw_prefix.imagelinks (il_to,il_from);
+
+
+CREATE TABLE &mw_prefix.categorylinks (
+  cl_from       NUMBER      NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  cl_to         VARCHAR2(255)         NOT NULL,
+  cl_sortkey    VARCHAR2(255),
+  cl_timestamp  TIMESTAMP(6) WITH TIME ZONE  NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.categorylinks_u01 ON &mw_prefix.categorylinks (cl_from,cl_to);
+CREATE INDEX &mw_prefix.categorylinks_i01 ON &mw_prefix.categorylinks (cl_to,cl_sortkey,cl_from);
+CREATE INDEX &mw_prefix.categorylinks_i02 ON &mw_prefix.categorylinks (cl_to,cl_timestamp);
+
+CREATE SEQUENCE category_cat_id_val;
+CREATE TABLE &mw_prefix.category (
+  cat_id NUMBER NOT NULL,
+  cat_title VARCHAR2(255) NOT NULL,
+  cat_pages NUMBER DEFAULT 0 NOT NULL,
+  cat_subcats NUMBER DEFAULT 0 NOT NULL,
+  cat_files NUMBER DEFAULT 0 NOT NULL,
+  cat_hidden NUMBER DEFAULT 0 NOT NULL
+);
+ALTER TABLE &mw_prefix.category ADD CONSTRAINT &mw_prefix.category_pk PRIMARY KEY (cat_id);
+CREATE UNIQUE INDEX &mw_prefix.category_u01 ON &mw_prefix.category (cat_title);
+CREATE INDEX &mw_prefix.category_i01 ON &mw_prefix.category (cat_pages);
+
+CREATE TABLE &mw_prefix.externallinks (
+  el_from   NUMBER  NOT NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  el_to     VARCHAR2(2048) NOT NULL,
+  el_index  VARCHAR2(2048) NOT NULL
+);
+CREATE INDEX &mw_prefix.externallinks_i01 ON &mw_prefix.externallinks (el_from, el_to);
+CREATE INDEX &mw_prefix.externallinks_i02 ON &mw_prefix.externallinks (el_to, el_from);
+CREATE INDEX &mw_prefix.externallinks_i03 ON &mw_prefix.externallinks (el_index);
+
+CREATE TABLE &mw_prefix.langlinks (
+  ll_from    NUMBER  NOT NULL  REFERENCES &mw_prefix.page (page_id) ON DELETE CASCADE,
+  ll_lang    VARCHAR2(20),
+  ll_title   VARCHAR2(255)
+);
+CREATE UNIQUE INDEX &mw_prefix.langlinks_u01 ON &mw_prefix.langlinks (ll_from, ll_lang);
+CREATE INDEX &mw_prefix.langlinks_i01 ON &mw_prefix.langlinks (ll_lang, ll_title);
+
+CREATE TABLE &mw_prefix.site_stats (
+  ss_row_id         NUMBER  NOT NULL ,
+  ss_total_views    NUMBER            DEFAULT 0,
+  ss_total_edits    NUMBER            DEFAULT 0,
+  ss_good_articles  NUMBER            DEFAULT 0,
+  ss_total_pages    NUMBER            DEFAULT -1,
+  ss_users          NUMBER            DEFAULT -1,
+  ss_active_users   NUMBER            DEFAULT -1,
+  ss_admins         NUMBER            DEFAULT -1,
+  ss_images         NUMBER            DEFAULT 0
+);
+CREATE UNIQUE INDEX &mw_prefix.site_stats_u01 ON &mw_prefix.site_stats (ss_row_id);
+
+CREATE TABLE &mw_prefix.hitcounter (
+  hc_id  NUMBER  NOT NULL
 );
 
-CREATE TABLE hitcounter (
-  hc_id  INTEGER  NOT NULL
-);
-
-
 CREATE SEQUENCE ipblocks_ipb_id_val;
-CREATE TABLE ipblocks (
-  ipb_id                INTEGER      NOT NULL PRIMARY KEY,
-  ipb_address           VARCHAR(255)     NULL,
-  ipb_user              INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  ipb_by                INTEGER      NOT NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE,
-  ipb_reason            VARCHAR(255)         NOT NULL,
-  ipb_timestamp         TIMESTAMP WITH TIME ZONE  NOT NULL,
-  ipb_auto              CHAR         DEFAULT '0' NOT NULL,
-  ipb_anon_only         CHAR         DEFAULT '0' NOT NULL,
-  ipb_create_account    CHAR         DEFAULT '1' NOT NULL,
-  ipb_enable_autoblock  CHAR         DEFAULT '1' NOT NULL,
-  ipb_expiry            TIMESTAMP WITH TIME ZONE  NOT NULL,
-  ipb_range_start       CHAR(8),
-  ipb_range_end         CHAR(8),
-  ipb_deleted           INTEGER      DEFAULT '0' NOT NULL
-);
-CREATE INDEX ipb_address ON ipblocks (ipb_address);
-CREATE INDEX ipb_user    ON ipblocks (ipb_user);
-CREATE INDEX ipb_range   ON ipblocks (ipb_range_start,ipb_range_end);
-
+CREATE TABLE &mw_prefix.ipblocks (
+  ipb_id                NUMBER      NOT NULL,
+  ipb_address           VARCHAR2(255)     NULL,
+  ipb_user              NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  ipb_by                NUMBER      NOT NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE,
+  ipb_by_text           VARCHAR2(255)      NOT NULL,
+  ipb_reason            VARCHAR2(255)         NOT NULL,
+  ipb_timestamp         TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  ipb_auto              CHAR(1)         DEFAULT '0' NOT NULL,
+  ipb_anon_only         CHAR(1)         DEFAULT '0' NOT NULL,
+  ipb_create_account    CHAR(1)         DEFAULT '1' NOT NULL,
+  ipb_enable_autoblock  CHAR(1)         DEFAULT '1' NOT NULL,
+  ipb_expiry            TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  ipb_range_start       VARCHAR2(255),
+  ipb_range_end         VARCHAR2(255),
+  ipb_deleted           CHAR(1)      DEFAULT '0' NOT NULL,
+  ipb_block_email       CHAR(1)      DEFAULT '0' NOT NULL,
+  ipb_allow_usertalk    CHAR(1)      DEFAULT '0' NOT NULL
+);
+ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_pk PRIMARY KEY (ipb_id);
+CREATE UNIQUE INDEX &mw_prefix.ipblocks_u01 ON &mw_prefix.ipblocks (ipb_address, ipb_user, ipb_auto, ipb_anon_only);
+CREATE INDEX &mw_prefix.ipblocks_i01 ON &mw_prefix.ipblocks (ipb_user);
+CREATE INDEX &mw_prefix.ipblocks_i02 ON &mw_prefix.ipblocks (ipb_range_start, ipb_range_end);
+CREATE INDEX &mw_prefix.ipblocks_i03 ON &mw_prefix.ipblocks (ipb_timestamp);
+CREATE INDEX &mw_prefix.ipblocks_i04 ON &mw_prefix.ipblocks (ipb_expiry);
 
 CREATE TABLE image (
-  img_name         VARCHAR(255)      NOT NULL  PRIMARY KEY,
-  img_size         INTEGER   NOT NULL,
-  img_width        INTEGER   NOT NULL,
-  img_height       INTEGER   NOT NULL,
+  img_name         VARCHAR2(255)      NOT NULL,
+  img_size         NUMBER   NOT NULL,
+  img_width        NUMBER   NOT NULL,
+  img_height       NUMBER   NOT NULL,
   img_metadata     CLOB,
-  img_bits         SMALLINT,
-  img_media_type   CLOB,
-  img_major_mime   CLOB                DEFAULT 'unknown',
-  img_minor_mime   CLOB                DEFAULT 'unknown',
-  img_description  CLOB,
-  img_user         INTEGER       NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  img_user_text    CLOB      NOT NULL,
-  img_timestamp    TIMESTAMP WITH TIME ZONE
-);
-CREATE INDEX img_size_idx      ON image (img_size);
-CREATE INDEX img_timestamp_idx ON image (img_timestamp);
-
-CREATE TABLE oldimage (
-  oi_name          VARCHAR(255)         NOT NULL  REFERENCES image(img_name),
-  oi_archive_name  VARCHAR(255),
-  oi_size          INTEGER      NOT NULL,
-  oi_width         INTEGER      NOT NULL,
-  oi_height        INTEGER      NOT NULL,
-  oi_bits          SMALLINT     NOT NULL,
-  oi_description   CLOB,
-  oi_user          INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  oi_user_text     CLOB         NOT NULL,
-  oi_timestamp     TIMESTAMP WITH TIME ZONE  NOT NULL,
-  oi_metadata      CLOB,        
-  oi_media_type    VARCHAR(10) DEFAULT NULL,
-  oi_major_mime    VARCHAR(11) DEFAULT 'unknown',
-  oi_minor_mime    VARCHAR(32) DEFAULT 'unknown',
-  oi_deleted       INTEGER DEFAULT 0 NOT NULL
-);
-CREATE INDEX oi_name_timestamp ON oldimage (oi_name,oi_timestamp);
-CREATE INDEX oi_name_archive_name ON oldimage (oi_name,oi_archive_name);
+  img_bits         NUMBER,
+  img_media_type   VARCHAR2(32),
+  img_major_mime   VARCHAR2(32) DEFAULT 'unknown',
+  img_minor_mime   VARCHAR2(32) DEFAULT 'unknown',
+  img_description  VARCHAR2(255),
+  img_user         NUMBER       NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  img_user_text    VARCHAR2(255)      NOT NULL,
+  img_timestamp    TIMESTAMP(6) WITH TIME ZONE,
+       img_sha1         VARCHAR2(32)
+);
+ALTER TABLE &mw_prefix.image ADD CONSTRAINT &mw_prefix.image_pk PRIMARY KEY (img_name);
+CREATE INDEX &mw_prefix.image_i01 ON &mw_prefix.image (img_user_text,img_timestamp);
+CREATE INDEX &mw_prefix.image_i02 ON &mw_prefix.image (img_size);
+CREATE INDEX &mw_prefix.image_i03 ON &mw_prefix.image (img_timestamp);
+CREATE INDEX &mw_prefix.image_i04 ON &mw_prefix.image (img_sha1);
+
+
+CREATE TABLE &mw_prefix.oldimage (
+  oi_name          VARCHAR2(255)         NOT NULL  REFERENCES &mw_prefix.image(img_name),
+  oi_archive_name  VARCHAR2(255),
+  oi_size          NUMBER      NOT NULL,
+  oi_width         NUMBER      NOT NULL,
+  oi_height        NUMBER      NOT NULL,
+  oi_bits          NUMBER     NOT NULL,
+  oi_description   VARCHAR2(255),
+  oi_user          NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  oi_user_text     VARCHAR2(255)         NOT NULL,
+  oi_timestamp     TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  oi_metadata      CLOB,
+  oi_media_type    VARCHAR2(32) DEFAULT NULL,
+  oi_major_mime    VARCHAR2(32) DEFAULT 'unknown',
+  oi_minor_mime    VARCHAR2(32) DEFAULT 'unknown',
+  oi_deleted       NUMBER DEFAULT 0 NOT NULL,
+  oi_sha1          VARCHAR2(32)
+);
+CREATE INDEX &mw_prefix.oldimage_i01 ON &mw_prefix.oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX &mw_prefix.oldimage_i02 ON &mw_prefix.oldimage (oi_name,oi_timestamp);
+CREATE INDEX &mw_prefix.oldimage_i03 ON &mw_prefix.oldimage (oi_name,oi_archive_name);
+CREATE INDEX &mw_prefix.oldimage_i04 ON &mw_prefix.oldimage (oi_sha1);
+
 
 CREATE SEQUENCE filearchive_fa_id_seq;
-CREATE TABLE filearchive (
-  fa_id                 INTEGER       NOT NULL  PRIMARY KEY,
-  fa_name               VARCHAR(255)         NOT NULL,
-  fa_archive_name       VARCHAR(255),
-  fa_storage_group      VARCHAR(16),
-  fa_storage_key        CHAR(64),
-  fa_deleted_user       INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  fa_deleted_timestamp  TIMESTAMP WITH TIME ZONE  NOT NULL,
+CREATE TABLE &mw_prefix.filearchive (
+  fa_id                 NUMBER       NOT NULL,
+  fa_name               VARCHAR2(255)         NOT NULL,
+  fa_archive_name       VARCHAR2(255),
+  fa_storage_group      VARCHAR2(16),
+  fa_storage_key        VARCHAR2(64),
+  fa_deleted_user       NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  fa_deleted_timestamp  TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
   fa_deleted_reason     CLOB,
-  fa_size               SMALLINT     NOT NULL,
-  fa_width              SMALLINT     NOT NULL,
-  fa_height             SMALLINT     NOT NULL,
+  fa_size               NUMBER     NOT NULL,
+  fa_width              NUMBER     NOT NULL,
+  fa_height             NUMBER     NOT NULL,
   fa_metadata           CLOB,
-  fa_bits               SMALLINT,
-  fa_media_type         CLOB,
-  fa_major_mime         CLOB                   DEFAULT 'unknown',
-  fa_minor_mime         CLOB                   DEFAULT 'unknown',
-  fa_description        CLOB         NOT NULL,
-  fa_user               INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  fa_user_text          CLOB         NOT NULL,
-  fa_timestamp          TIMESTAMP WITH TIME ZONE,
-  fa_deleted            INTEGER      DEFAULT '0' NOT NULL
-);
-CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp);
-CREATE INDEX fa_dupe      ON filearchive (fa_storage_group, fa_storage_key);
-CREATE INDEX fa_notime    ON filearchive (fa_deleted_timestamp);
-CREATE INDEX fa_nouser    ON filearchive (fa_deleted_user);
-
+  fa_bits               NUMBER,
+  fa_media_type         VARCHAR2(32) DEFAULT NULL,
+  fa_major_mime         VARCHAR2(32) DEFAULT 'unknown',
+  fa_minor_mime         VARCHAR2(32) DEFAULT 'unknown',
+  fa_description        VARCHAR2(255)         NOT NULL,
+  fa_user               NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  fa_user_text          VARCHAR2(255)         NOT NULL,
+  fa_timestamp          TIMESTAMP(6) WITH TIME ZONE,
+  fa_deleted            NUMBER      DEFAULT '0' NOT NULL
+);
+ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_pk PRIMARY KEY (fa_id);
+CREATE INDEX &mw_prefix.filearchive_i01 ON &mw_prefix.filearchive (fa_name, fa_timestamp);
+CREATE INDEX &mw_prefix.filearchive_i02 ON &mw_prefix.filearchive (fa_storage_group, fa_storage_key);
+CREATE INDEX &mw_prefix.filearchive_i03 ON &mw_prefix.filearchive (fa_deleted_timestamp);
+CREATE INDEX &mw_prefix.filearchive_i04 ON &mw_prefix.filearchive (fa_user_text,fa_timestamp);
 
 CREATE SEQUENCE rc_rc_id_seq;
-CREATE TABLE recentchanges (
-  rc_id              INTEGER      NOT NULL PRIMARY KEY,
-  rc_timestamp       TIMESTAMP WITH TIME ZONE  NOT NULL,
-  rc_cur_time        TIMESTAMP WITH TIME ZONE  NOT NULL,
-  rc_user            INTEGER          NULL  REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  rc_user_text       CLOB         NOT NULL,
-  rc_namespace       SMALLINT     NOT NULL,
-  rc_title           VARCHAR(255)         NOT NULL,
-  rc_comment         VARCHAR(255),
-  rc_minor           CHAR         DEFAULT '0' NOT NULL,
-  rc_bot             CHAR         DEFAULT '0' NOT NULL,
-  rc_new             CHAR         DEFAULT '0' NOT NULL,
-  rc_cur_id          INTEGER          NULL  REFERENCES page(page_id) ON DELETE SET NULL,
-  rc_this_oldid      INTEGER      NOT NULL,
-  rc_last_oldid      INTEGER      NOT NULL,
-  rc_type            CHAR         DEFAULT '0' NOT NULL,
-  rc_moved_to_ns     SMALLINT,
-  rc_moved_to_title  CLOB,
-  rc_patrolled       CHAR         DEFAULT '0' NOT NULL,
-  rc_ip              VARCHAR(15),
-  rc_old_len         INTEGER,
-  rc_new_len         INTEGER,
-  rc_deleted         INTEGER      DEFAULT '0' NOT NULL,
-  rc_logid           INTEGER      DEFAULT '0' NOT NULL,
-  rc_log_type           CLOB,
-  rc_log_action      CLOB,
-  rc_params             CLOB
-);
-CREATE INDEX rc_timestamp       ON recentchanges (rc_timestamp);
-CREATE INDEX rc_namespace_title ON recentchanges (rc_namespace, rc_title);
-CREATE INDEX rc_cur_id          ON recentchanges (rc_cur_id);
-CREATE INDEX new_name_timestamp ON recentchanges (rc_new, rc_namespace, rc_timestamp);
-CREATE INDEX rc_ip              ON recentchanges (rc_ip);
-
-
-CREATE TABLE watchlist (
-  wl_user                   INTEGER     NOT NULL  REFERENCES mwuser(user_id) ON DELETE CASCADE,
-  wl_namespace              SMALLINT    DEFAULT 0 NOT NULL,
-  wl_title                  VARCHAR(255)        NOT NULL,
-  wl_notificationtimestamp  TIMESTAMP WITH TIME ZONE
-);
-CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title, wl_user);
-
-
-CREATE TABLE math (
-  math_inputhash              VARCHAR(16)      NOT NULL  UNIQUE,
-  math_outputhash             VARCHAR(16)      NOT NULL,
-  math_html_conservativeness  SMALLINT  NOT NULL,
+CREATE TABLE &mw_prefix.recentchanges (
+  rc_id              NUMBER      NOT NULL,
+  rc_timestamp       TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  rc_cur_time        TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  rc_user            NUMBER          NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  rc_user_text       VARCHAR2(255)         NOT NULL,
+  rc_namespace       NUMBER     NOT NULL,
+  rc_title           VARCHAR2(255)         NOT NULL,
+  rc_comment         VARCHAR2(255),
+  rc_minor           CHAR(1)         DEFAULT '0' NOT NULL,
+  rc_bot             CHAR(1)         DEFAULT '0' NOT NULL,
+  rc_new             CHAR(1)         DEFAULT '0' NOT NULL,
+  rc_cur_id          NUMBER          NULL  REFERENCES &mw_prefix.page(page_id) ON DELETE SET NULL,
+  rc_this_oldid      NUMBER      NOT NULL,
+  rc_last_oldid      NUMBER      NOT NULL,
+  rc_type            CHAR(1)         DEFAULT '0' NOT NULL,
+  rc_moved_to_ns     NUMBER,
+  rc_moved_to_title  VARCHAR2(255),
+  rc_patrolled       CHAR(1)         DEFAULT '0' NOT NULL,
+  rc_ip              VARCHAR2(15),
+  rc_old_len         NUMBER,
+  rc_new_len         NUMBER,
+  rc_deleted         NUMBER      DEFAULT '0' NOT NULL,
+  rc_logid           NUMBER      DEFAULT '0' NOT NULL,
+  rc_log_type        VARCHAR2(255),
+  rc_log_action      VARCHAR2(255),
+  rc_params          CLOB
+);
+ALTER TABLE &mw_prefix.recentchanges ADD CONSTRAINT &mw_prefix.recentchanges_pk PRIMARY KEY (rc_id);
+CREATE INDEX &mw_prefix.recentchanges_i01 ON &mw_prefix.recentchanges (rc_timestamp);
+CREATE INDEX &mw_prefix.recentchanges_i02 ON &mw_prefix.recentchanges (rc_namespace, rc_title);
+CREATE INDEX &mw_prefix.recentchanges_i03 ON &mw_prefix.recentchanges (rc_cur_id);
+CREATE INDEX &mw_prefix.recentchanges_i04 ON &mw_prefix.recentchanges (rc_new,rc_namespace,rc_timestamp);
+CREATE INDEX &mw_prefix.recentchanges_i05 ON &mw_prefix.recentchanges (rc_ip);
+CREATE INDEX &mw_prefix.recentchanges_i06 ON &mw_prefix.recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX &mw_prefix.recentchanges_i07 ON &mw_prefix.recentchanges (rc_user_text, rc_timestamp);
+
+CREATE TABLE &mw_prefix.watchlist (
+  wl_user                   NUMBER     NOT NULL  REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE,
+  wl_namespace              NUMBER    DEFAULT 0 NOT NULL,
+  wl_title                  VARCHAR2(255)        NOT NULL,
+  wl_notificationtimestamp  TIMESTAMP(6) WITH TIME ZONE
+);
+CREATE UNIQUE INDEX &mw_prefix.watchlist_u01 ON &mw_prefix.watchlist (wl_user, wl_namespace, wl_title);
+CREATE INDEX &mw_prefix.watchlist_i01 ON &mw_prefix.watchlist (wl_namespace, wl_title);
+
+
+CREATE TABLE &mw_prefix.math (
+  math_inputhash              VARCHAR2(16)      NOT NULL,
+  math_outputhash             VARCHAR2(16)      NOT NULL,
+  math_html_conservativeness  NUMBER  NOT NULL,
   math_html                   CLOB,
   math_mathml                 CLOB
 );
+CREATE UNIQUE INDEX &mw_prefix.math_u01 ON &mw_prefix.math (math_inputhash);
 
-
-CREATE TABLE interwiki (
-  iw_prefix  VARCHAR(32)   NOT NULL  UNIQUE,
-  iw_url     VARCHAR(127)  NOT NULL,
-  iw_local   CHAR  NOT NULL,
-  iw_trans   CHAR  DEFAULT '0' NOT NULL
-);
-
-CREATE TABLE querycache (
-  qc_type       CHAR(32)      NOT NULL,
-  qc_value      SMALLINT  NOT NULL,
-  qc_namespace  SMALLINT  NOT NULL,
-  qc_title      CHAR(255)      NOT NULL
+CREATE TABLE &mw_prefix.searchindex (
+  si_page      NUMBER NOT NULL,
+  si_title     VARCHAR2(255) DEFAULT '' NOT NULL,
+  si_text      CLOB NOT NULL
 );
-CREATE INDEX querycache_type_value ON querycache (qc_type, qc_value);
+CREATE UNIQUE INDEX &mw_prefix.searchindex_u01 ON &mw_prefix.searchindex (si_page);
 
-CREATE TABLE querycache_info (
-  qci_type       VARCHAR(32)              UNIQUE,
-  qci_timestamp  TIMESTAMP WITH TIME ZONE NULL
+CREATE TABLE &mw_prefix.interwiki (
+  iw_prefix  VARCHAR2(32)   NOT NULL,
+  iw_url     VARCHAR2(127)  NOT NULL,
+  iw_local   CHAR(1)  NOT NULL,
+  iw_trans   CHAR(1)  DEFAULT '0' NOT NULL
 );
+CREATE UNIQUE INDEX &mw_prefix.interwiki_u01 ON &mw_prefix.interwiki (iw_prefix);
 
-CREATE TABLE querycachetwo (
-  qcc_type          CHAR(32)     NOT NULL,
-  qcc_value         SMALLINT DEFAULT 0 NOT NULL,
-  qcc_namespace     INTEGER  DEFAULT 0 NOT NULL,
-  qcc_title         CHAR(255)     DEFAULT '' NOT NULL,
-  qcc_namespacetwo  INTEGER  DEFAULT 0 NOT NULL,
-  qcc_titletwo      CHAR(255)     DEFAULT '' NOT NULL
+CREATE TABLE &mw_prefix.querycache (
+  qc_type       VARCHAR2(32)      NOT NULL,
+  qc_value      NUMBER  NOT NULL,
+  qc_namespace  NUMBER  NOT NULL,
+  qc_title      VARCHAR2(255)      NOT NULL
 );
-CREATE INDEX querycachetwo_type_value ON querycachetwo (qcc_type, qcc_value);
-CREATE INDEX querycachetwo_title      ON querycachetwo (qcc_type,qcc_namespace,qcc_title);
-CREATE INDEX querycachetwo_titletwo   ON querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo);
+CREATE INDEX &mw_prefix.querycache_u01 ON &mw_prefix.querycache (qc_type,qc_value);
 
-
-CREATE TABLE objectcache (
-  keyname  CHAR(255)              UNIQUE,
+CREATE TABLE &mw_prefix.objectcache (
+  keyname  VARCHAR2(255)              ,
   value    BLOB,
-  exptime  TIMESTAMP WITH TIME ZONE  NOT NULL
+  exptime  TIMESTAMP(6) WITH TIME ZONE  NOT NULL
 );
-CREATE INDEX objectcacache_exptime ON objectcache (exptime);
+CREATE INDEX &mw_prefix.objectcache_i01 ON &mw_prefix.objectcache (exptime);
 
-CREATE TABLE transcache (
-  tc_url       VARCHAR(255)         NOT NULL  UNIQUE,
+CREATE TABLE &mw_prefix.transcache (
+  tc_url       VARCHAR2(255)         NOT NULL,
   tc_contents  CLOB         NOT NULL,
-  tc_time      TIMESTAMP WITH TIME ZONE  NOT NULL
+  tc_time      TIMESTAMP(6) WITH TIME ZONE  NOT NULL
 );
+CREATE UNIQUE INDEX &mw_prefix.transcache_u01 ON &mw_prefix.transcache (tc_url);
 
 
 CREATE SEQUENCE log_log_id_seq;
-CREATE TABLE logging (
-  log_type        VARCHAR(10)         NOT NULL,
-  log_action      VARCHAR(10)         NOT NULL,
-  log_timestamp   TIMESTAMP WITH TIME ZONE  NOT NULL,
-  log_user        INTEGER                REFERENCES mwuser(user_id) ON DELETE SET NULL,
-  log_namespace   SMALLINT     NOT NULL,
-  log_title       VARCHAR(255)         NOT NULL,
-  log_comment     VARCHAR(255),
+CREATE TABLE &mw_prefix.logging (
+  log_id          NUMBER      NOT NULL,
+  log_type        VARCHAR2(10)         NOT NULL,
+  log_action      VARCHAR2(10)         NOT NULL,
+  log_timestamp   TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  log_user        NUMBER                REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL,
+  log_namespace   NUMBER     NOT NULL,
+  log_title       VARCHAR2(255)         NOT NULL,
+  log_comment     VARCHAR2(255),
   log_params      CLOB,
-  log_deleted     INTEGER      DEFAULT '0' NOT NULL,
-  log_id          INTEGER      NOT NULL PRIMARY KEY
+  log_deleted     NUMBER      DEFAULT '0' NOT NULL
+);
+ALTER TABLE &mw_prefix.logging ADD CONSTRAINT &mw_prefix.logging_pk PRIMARY KEY (log_id);
+CREATE INDEX &mw_prefix.logging_i01 ON &mw_prefix.logging (log_type, log_timestamp);
+CREATE INDEX &mw_prefix.logging_i02 ON &mw_prefix.logging (log_user, log_timestamp);
+CREATE INDEX &mw_prefix.logging_i03 ON &mw_prefix.logging (log_namespace, log_title, log_timestamp);
+CREATE INDEX &mw_prefix.logging_i04 ON &mw_prefix.logging (log_timestamp);
+
+CREATE TABLE &mw_prefix.log_search (
+  ls_field VARCHAR2(32) NOT NULL,
+  ls_value VARCHAR2(255) NOT NULL,
+  ls_log_id NuMBER DEFAULT 0 NOT NULL
 );
-CREATE INDEX logging_type_name ON logging (log_type, log_timestamp);
-CREATE INDEX logging_user_time ON logging (log_timestamp, log_user);
-CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timestamp);
+ALTER TABLE log_search ADD CONSTRAINT log_search_pk PRIMARY KEY (ls_field,ls_value,ls_log_id);
+CREATE INDEX &mw_prefix.log_search_i01 ON &mw_prefix.log_search (ls_log_id);
 
 CREATE SEQUENCE trackbacks_tb_id_seq;
-CREATE TABLE trackbacks (
-  tb_id     INTEGER   NOT NULL PRIMARY KEY,
-  tb_page   INTEGER            REFERENCES page(page_id) ON DELETE CASCADE,
-  tb_title  VARCHAR(255)     NOT NULL,
-  tb_url    VARCHAR(255)     NOT NULL,
+CREATE TABLE &mw_prefix.trackbacks (
+  tb_id     NUMBER   NOT NULL,
+  tb_page   NUMBER            REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE,
+  tb_title  VARCHAR2(255)     NOT NULL,
+  tb_url    VARCHAR2(255)     NOT NULL,
   tb_ex     CLOB,
-  tb_name   VARCHAR(255) 
+  tb_name   VARCHAR2(255) 
 );
-CREATE INDEX trackback_page ON trackbacks (tb_page);
+ALTER TABLE &mw_prefix.trackbacks ADD CONSTRAINT &mw_prefix.trackbacks_pk PRIMARY KEY (tb_id);
+CREATE INDEX &mw_prefix.trackbacks_i01 ON &mw_prefix.trackbacks (tb_page);
 
 CREATE SEQUENCE job_job_id_seq;
-CREATE TABLE job (
-  job_id         INTEGER   NOT NULL PRIMARY KEY,
-  job_cmd        VARCHAR(255)      NOT NULL,
-  job_namespace  SMALLINT  NOT NULL,
-  job_title      VARCHAR(255)      NOT NULL,
+CREATE TABLE &mw_prefix.job (
+  job_id         NUMBER   NOT NULL,
+  job_cmd        VARCHAR2(60)      NOT NULL,
+  job_namespace  NUMBER  NOT NULL,
+  job_title      VARCHAR2(255)      NOT NULL,
   job_params     CLOB      NOT NULL
 );
-CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title);
+ALTER TABLE &mw_prefix.job ADD CONSTRAINT &mw_prefix.job_pk PRIMARY KEY (job_id);
+CREATE INDEX &mw_prefix.job_i01 ON &mw_prefix.job (job_cmd, job_namespace, job_title);
+
+CREATE TABLE &mw_prefix.querycache_info (
+  qci_type       VARCHAR2(32) NOT NULL,
+  qci_timestamp  TIMESTAMP(6) WITH TIME ZONE NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.querycache_info_u01 ON &mw_prefix.querycache_info (qci_type);
+
+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
+);
+CREATE INDEX &mw_prefix.redirect_i01 ON &mw_prefix.redirect (rd_namespace,rd_title,rd_from);
+
+CREATE TABLE &mw_prefix.querycachetwo (
+  qcc_type          VARCHAR2(32)     NOT NULL,
+  qcc_value         NUMBER  DEFAULT 0 NOT NULL,
+  qcc_namespace     NUMBER  DEFAULT 0 NOT NULL,
+  qcc_title         VARCHAR2(255)     DEFAULT '' NOT NULL,
+  qcc_namespacetwo  NUMBER  DEFAULT 0 NOT NULL,
+  qcc_titletwo      VARCHAR2(255)     DEFAULT '' NOT NULL
+);
+CREATE INDEX &mw_prefix.querycachetwo_i01 ON &mw_prefix.querycachetwo (qcc_type,qcc_value);
+CREATE INDEX &mw_prefix.querycachetwo_i02 ON &mw_prefix.querycachetwo (qcc_type,qcc_namespace,qcc_title);
+CREATE INDEX &mw_prefix.querycachetwo_i03 ON &mw_prefix.querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo);
+
+CREATE SEQUENCE pr_id_val;
+CREATE TABLE &mw_prefix.page_restrictions (
+  pr_id      NUMBER      NOT NULL,
+  pr_page    NUMBER          NULL  REFERENCES &mw_prefix.page (page_id) ON DELETE CASCADE,
+  pr_type    VARCHAR2(255)         NOT NULL,
+  pr_level   VARCHAR2(255)         NOT NULL,
+  pr_cascade NUMBER     NOT NULL,
+  pr_user    NUMBER          NULL,
+  pr_expiry  TIMESTAMP(6) WITH TIME ZONE      NULL
+);
+ALTER TABLE &mw_prefix.page_restrictions ADD CONSTRAINT &mw_prefix.page_restrictions_pk PRIMARY KEY (pr_page,pr_type);
+CREATE INDEX &mw_prefix.page_restrictions_i01 ON &mw_prefix.page_restrictions (pr_type,pr_level);
+CREATE INDEX &mw_prefix.page_restrictions_i02 ON &mw_prefix.page_restrictions (pr_level);
+CREATE INDEX &mw_prefix.page_restrictions_i03 ON &mw_prefix.page_restrictions (pr_cascade);
+
+CREATE TABLE &mw_prefix.protected_titles (
+  pt_namespace   NUMBER           NOT NULL,
+  pt_title       VARCHAR2(255)    NOT NULL,
+  pt_user        NUMBER                  NOT NULL,
+  pt_reason      VARCHAR2(255),
+  pt_timestamp   TIMESTAMP(6) WITH TIME ZONE  NOT NULL,
+  pt_expiry      VARCHAR2(14) NOT NULL,
+  pt_create_perm VARCHAR2(60) NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.protected_titles_u01 ON &mw_prefix.protected_titles (pt_namespace,pt_title);
+CREATE INDEX &mw_prefix.protected_titles_i01 ON &mw_prefix.protected_titles (pt_timestamp);
+
+CREATE TABLE &mw_prefix.page_props (
+  pp_page NUMBER NOT NULL,
+  pp_propname VARCHAR2(60) NOT NULL,
+  pp_value BLOB NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.page_props_u01 ON &mw_prefix.page_props (pp_page,pp_propname);
+
+
+CREATE TABLE &mw_prefix.updatelog (
+  ul_key VARCHAR2(255) NOT NULL
+);
+ALTER TABLE &mw_prefix.updatelog ADD CONSTRAINT &mw_prefix.updatelog_pk PRIMARY KEY (ul_key);
+
+CREATE TABLE &mw_prefix.change_tag (
+  ct_rc_id NUMBER NULL,
+  ct_log_id NUMBER NULL,
+  ct_rev_id NUMBER NULL,
+  ct_tag VARCHAR2(255) NOT NULL,
+  ct_params BLOB NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.change_tag_u01 ON &mw_prefix.change_tag (ct_rc_id,ct_tag);
+CREATE UNIQUE INDEX &mw_prefix.change_tag_u02 ON &mw_prefix.change_tag (ct_log_id,ct_tag);
+CREATE UNIQUE INDEX &mw_prefix.change_tag_u03 ON &mw_prefix.change_tag (ct_rev_id,ct_tag);
+CREATE INDEX &mw_prefix.change_tag_i01 ON &mw_prefix.change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
+
+CREATE TABLE &mw_prefix.tag_summary (
+  ts_rc_id NUMBER NULL,
+  ts_log_id NUMBER NULL,
+  ts_rev_id NUMBER NULL,
+  ts_tags BLOB NOT NULL
+);
+CREATE UNIQUE INDEX &mw_prefix.tag_summary_u01 ON &mw_prefix.tag_summary (ts_rc_id);
+CREATE UNIQUE INDEX &mw_prefix.tag_summary_u02 ON &mw_prefix.tag_summary (ts_log_id);
+CREATE UNIQUE INDEX &mw_prefix.tag_summary_u03 ON &mw_prefix.tag_summary (ts_rev_id);
+
+CREATE TABLE &mw_prefix.valid_tag (
+  vt_tag VARCHAR2(255) NOT NULL
+);
+ALTER TABLE &mw_prefix.valid_tag ADD CONSTRAINT &mw_prefix.valid_tag_pk PRIMARY KEY (vt_tag);
 
 -- This table is not used unless profiling is turned on
---CREATE TABLE profiling (
---  pf_count   INTEGER         DEFAULT 0 NOT NULL,
+--CREATE TABLE &mw_prefix.profiling (
+--  pf_count   NUMBER         DEFAULT 0 NOT NULL,
 --  pf_time    NUMERIC(18,10)  DEFAULT 0 NOT NULL,
 --  pf_name    CLOB            NOT NULL,
 --  pf_server  CLOB            NULL
 --);
---CREATE UNIQUE INDEX pf_name_server ON profiling (pf_name, pf_server);
-
-CREATE TABLE searchindex (
-  si_page      INTEGER UNIQUE NOT NULL,
-  si_title     VARCHAR(255) DEFAULT '' NOT NULL,
-  si_text      CLOB NOT NULL
-);
-
-
-CREATE INDEX si_title_idx ON searchindex(si_title) INDEXTYPE IS ctxsys.context;
-CREATE INDEX si_text_idx ON searchindex(si_text) INDEXTYPE IS ctxsys.context;
+--CREATE UNIQUE INDEX &mw_prefix.profiling_u01 ON &mw_prefix.profiling (pf_name, pf_server);
+
+CREATE INDEX si_title_idx ON &mw_prefix.searchindex(si_title) INDEXTYPE IS ctxsys.context;
+CREATE INDEX si_text_idx ON &mw_prefix.searchindex(si_text) INDEXTYPE IS ctxsys.context;
+
+CREATE TABLE &mw_prefix.wiki_field_info_full (
+table_name VARCHAR2(35) NOT NULL,
+column_name VARCHAR2(35) NOT NULL,
+data_default VARCHAR2(4000),
+data_length NUMBER NOT NULL,
+data_type VARCHAR2(106),
+not_null CHAR(1) NOT NULL,
+prim NUMBER(1), 
+uniq NUMBER(1),
+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);
+
+CREATE PROCEDURE &mw_prefix.fill_wiki_info IS
+       BEGIN
+               DELETE      &mw_prefix.wiki_field_info_full;
+
+               FOR x_rec IN (SELECT '&mw_prefix.' || t.table_name table_name, t.column_name,
+                                                                                               t.data_default, t.data_length, t.data_type,
+                                                                                               DECODE (t.nullable, 'Y', '1', 'N', '0') not_null,
+                                                                                               (SELECT 1
+                                                                                                               FROM user_cons_columns ucc,
+                                                                                                                               user_constraints uc
+                                                                                                       WHERE ucc.table_name = t.table_name
+                                                                                                               AND ucc.column_name = t.column_name
+                                                                                                               AND uc.constraint_name = ucc.constraint_name
+                                                                                                               AND uc.constraint_type = 'P'
+                                                                                                               AND ROWNUM < 2) prim,
+                                                                                               (SELECT 1
+                                                                                                               FROM user_ind_columns uic,
+                                                                                                                               user_indexes ui
+                                                                                                       WHERE uic.table_name = t.table_name
+                                                                                                               AND uic.column_name = t.column_name
+                                                                                                               AND ui.index_name = uic.index_name
+                                                                                                               AND ui.uniqueness = 'UNIQUE'
+                                                                                                               AND ROWNUM < 2) uniq,
+                                                                                               (SELECT 1
+                                                                                                               FROM user_ind_columns uic,
+                                                                                                                               user_indexes ui
+                                                                                                       WHERE uic.table_name = t.table_name
+                                                                                                               AND uic.column_name = t.column_name
+                                                                                                               AND ui.index_name = uic.index_name
+                                                                                                               AND ui.uniqueness = 'NONUNIQUE'
+                                                                                                               AND ROWNUM < 2) nonuniq
+                                                                               FROM user_tab_columns t, user_tables ut
+                                                                       WHERE ut.table_name = t.table_name)
+               LOOP
+                       INSERT INTO &mw_prefix.wiki_field_info_full
+                                                                       (table_name, column_name,
+                                                                               data_default, data_length,
+                                                                               data_type, not_null, prim,
+                                                                               uniq, nonuniq
+                                                                       )
+                                               VALUES (x_rec.table_name, x_rec.column_name,
+                                                                               x_rec.data_default, x_rec.data_length,
+                                                                               x_rec.data_type, x_rec.not_null, x_rec.prim,
+                                                                               x_rec.uniq, x_rec.nonuniq
+                                                                       );
+               END LOOP;
+               COMMIT;
+END;
+
+BEGIN 
+       &mw_prefix.fill_wiki_info;
+END;
+
+CREATE OR REPLACE FUNCTION BITOR (x IN NUMBER, y IN NUMBER) RETURN NUMBER AS
+BEGIN
+  RETURN (x + y - BITAND(x, y));
+END;
diff --git a/maintenance/ora/user.sql b/maintenance/ora/user.sql
new file mode 100644 (file)
index 0000000..d5323d7
--- /dev/null
@@ -0,0 +1,13 @@
+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;