From: Jure Kajzer Date: Fri, 5 Jun 2009 11:45:32 +0000 (+0000) Subject: Oracle database abstraction updated. X-Git-Tag: 1.31.0-rc.0~41495 X-Git-Url: http://git.cyclocoop.org/%40spipnet%40?a=commitdiff_plain;h=da53ed0501fe467f01bdada16f727f8272daa4ab;p=lhc%2Fweb%2Fwiklou.git Oracle database abstraction updated. 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 --- diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 2f6ae1e2ee..974e4272c6 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -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 === diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 4e12e721e2..f1009ac657 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -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: diff --git a/includes/SearchOracle.php b/includes/SearchOracle.php index edb39a5594..b54fb859b9 100644 --- a/includes/SearchOracle.php +++ b/includes/SearchOracle.php @@ -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; diff --git a/includes/db/DatabaseOracle.php b/includes/db/DatabaseOracle.php index 3014d8cca1..a0700dbf63 100644 --- a/includes/db/DatabaseOracle.php +++ b/includes/db/DatabaseOracle.php @@ -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 } diff --git a/includes/specials/SpecialAncientpages.php b/includes/specials/SpecialAncientpages.php index 6ebd570ac9..18556c23bf 100644 --- a/includes/specials/SpecialAncientpages.php +++ b/includes/specials/SpecialAncientpages.php @@ -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, diff --git a/includes/specials/SpecialUnusedimages.php b/includes/specials/SpecialUnusedimages.php index fa66555d47..778bb0319b 100644 --- a/includes/specials/SpecialUnusedimages.php +++ b/includes/specials/SpecialUnusedimages.php @@ -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' ); diff --git a/maintenance/ora/tables.sql b/maintenance/ora/tables.sql index 6d4b8ed503..61211fba88 100644 --- a/maintenance/ora/tables.sql +++ b/maintenance/ora/tables.sql @@ -1,443 +1,630 @@ --- 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 index 0000000000..d5323d75e6 --- /dev/null +++ b/maintenance/ora/user.sql @@ -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;