? 'root@localhost'
: $_SERVER["SERVER_ADMIN"];
$conf->EmergencyContact = importPost( "EmergencyContact", $defaultEmail );
+ $conf->DBtype = importPost( "DBtype", "mysql" );
$conf->DBserver = importPost( "DBserver", "localhost" );
$conf->DBname = importPost( "DBname", "wikidb" );
$conf->DBuser = importPost( "DBuser", "wikiuser" );
$wgCommandLineMode = false;
chdir( ".." );
eval($local);
+ if (!in_array($conf->DBtype, array("mysql", "oracle"))) {
+ $errs["DBtype"] = "Unknown database type.";
+ continue;
+ }
+ print "<li>Database type: {$conf->DBtype}</li>\n";
+ $dbclass = 'Database'.ucfirst($conf->DBtype);
+ require_once("$dbclass.php");
+ $wgDBtype = $conf->DBtype;
$wgDBadminuser = "root";
$wgDBadminpassword = $conf->RootPW;
$wgDBprefix = $conf->DBprefix;
see <a href='http://dev.mysql.com/doc/mysql/en/old-client.html'
>http://dev.mysql.com/doc/mysql/en/old-client.html</a> for help.</b></li>\n";
}
- print "<li>Trying to connect to MySQL on $wgDBserver as root...\n";
- $wgDatabase = Database::newFromParams( $wgDBserver, "root", $conf->RootPW, "", 1 );
-
- if( $wgDatabase->isOpen() ) {
- $myver = mysql_get_server_info( $wgDatabase->mConn );
- $wgDatabase->ignoreErrors(true);
- $conf->Root = true;
- print "<ul><li>Connected as root (automatic)</li></ul></li>\n";
- } else {
- print "<ul><li>MySQL error " . ($err = mysql_errno() ) .
- ": " . htmlspecialchars( mysql_error() ) . "</li></ul></li>";
- $ok = false;
- switch( $err ) {
- case 1045:
- case 2000:
- if( $conf->Root ) {
- $errs["RootPW"] = "Check password";
- } else {
- print "<li>Trying regular user...\n";
- /* Try the regular user... */
- $wgDBadminuser = $wgDBuser;
- $wgDBadminpassword = $wgDBpassword;
- /* Wait one second for connection rate limiting, present on some systems */
- sleep(1);
- $wgDatabase = Database::newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, "", 1 );
- if( !$wgDatabase->isOpen() ) {
- print "<ul><li>MySQL error " . ($err = mysql_errno() ) .
- ": " . htmlspecialchars( mysql_error() ) . "</li></ul></li>";
- $errs["DBuser"] = "Check name/pass";
- $errs["DBpassword"] = "or enter root";
- $errs["DBpassword2"] = "password below";
- $errs["RootPW"] = "Got root?";
+ $dbc = new $dbclass;
+ if ($conf->DBtype == 'mysql') {
+ print "<li>Trying to connect to database server on $wgDBserver as root...\n";
+ $wgDatabase = $dbc->newFromParams( $wgDBserver, "root", $conf->RootPW, "", 1 );
+
+ if( $wgDatabase->isOpen() ) {
+ $myver = get_db_version();
+ $wgDatabase->ignoreErrors(true);
+ $conf->Root = true;
+ print "<ul><li>Connected as root (automatic)</li></ul></li>\n";
+ } else {
+ print "<ul><li>MySQL error " . ($err = mysql_errno() ) .
+ ": " . htmlspecialchars( mysql_error() ) . "</li></ul></li>";
+ $ok = false;
+ switch( $err ) {
+ case 1045:
+ case 2000:
+ if( $conf->Root ) {
+ $errs["RootPW"] = "Check password";
} else {
- $myver = mysql_get_server_info( $wgDatabase->mConn );
- $wgDatabase->ignoreErrors(true);
- $conf->Root = false;
- $conf->RootPW = "";
- print " ok.</li>\n";
- # And keep going...
- $ok = true;
+ print "<li>Trying regular user...\n";
+ /* Try the regular user... */
+ $wgDBadminuser = $wgDBuser;
+ $wgDBadminpassword = $wgDBpassword;
+ /* Wait one second for connection rate limiting, present on some systems */
+ sleep(1);
+ $wgDatabase = Database::newFromParams( $wgDBserver, $wgDBuser, $wgDBpassword, "", 1 );
+ if( !$wgDatabase->isOpen() ) {
+ print "<ul><li>MySQL error " . ($err = mysql_errno() ) .
+ ": " . htmlspecialchars( mysql_error() ) . "</li></ul></li>";
+ $errs["DBuser"] = "Check name/pass";
+ $errs["DBpassword"] = "or enter root";
+ $errs["DBpassword2"] = "password below";
+ $errs["RootPW"] = "Got root?";
+ } else {
+ $myver = mysql_get_server_info( $wgDatabase->mConn );
+ $wgDatabase->ignoreErrors(true);
+ $conf->Root = false;
+ $conf->RootPW = "";
+ print " ok.</li>\n";
+ # And keep going...
+ $ok = true;
+ }
+ break;
}
+ case 2002:
+ case 2003:
+ $errs["DBserver"] = "Connection failed";
+ break;
+ default:
+ $errs["DBserver"] = "Couldn't connect to database";
break;
}
- case 2002:
- case 2003:
- $errs["DBserver"] = "Connection failed";
- break;
- default:
- $errs["DBserver"] = "Couldn't connect to database";
- break;
+ if( !$ok ) continue;
+ }
+ } else /* not mysql */ {
+ print "<li>Connecting to SQL server...";
+ $wgDatabase = $dbc->newFromParams($wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, 1);
+ if (!$wgDatabase->isOpen()) {
+ print " error: " . $wgDatabase->lastError() . "</li>\n";
+ } else {
+ $wgDatabase->ignoreErrors(true);
+ $myver = get_db_version();
}
- if( !$ok ) continue;
}
if ( !$wgDatabase->isOpen() ) {
}
print "</li>\n";
- @$sel = mysql_select_db( $wgDBname, $wgDatabase->mConn );
- if( $sel ) {
- print "<li>Database <tt>" . htmlspecialchars( $wgDBname ) . "</tt> exists</li>\n";
- } else {
- $err = mysql_errno();
- if ( $err != 1049 ) {
- print "<ul><li>Error selecting database $wgDBname: $err " . htmlspecialchars( mysql_error() ) .
- "</li></ul>";
- continue;
- }
- $res = $wgDatabase->query( "CREATE DATABASE `$wgDBname`" );
- if( !$res ) {
- print "<li>Couldn't create database <tt>" .
- htmlspecialchars( $wgDBname ) .
- "</tt>; try with root access or check your username/pass.</li>\n";
- $errs["RootPW"] = "<- Enter";
- continue;
+ if ($conf->DBtype == 'mysql') {
+ @$sel = mysql_select_db( $wgDBname, $wgDatabase->mConn );
+ if( $sel ) {
+ print "<li>Database <tt>" . htmlspecialchars( $wgDBname ) . "</tt> exists</li>\n";
+ } else {
+ $err = mysql_errno();
+ if ( $err != 1049 ) {
+ print "<ul><li>Error selecting database $wgDBname: $err " .
+ htmlspecialchars( mysql_error() ) . "</li></ul>";
+ continue;
+ }
+ $res = $wgDatabase->query( "CREATE DATABASE `$wgDBname`" );
+ if( !$res ) {
+ print "<li>Couldn't create database <tt>" .
+ htmlspecialchars( $wgDBname ) .
+ "</tt>; try with root access or check your username/pass.</li>\n";
+ $errs["RootPW"] = "<- Enter";
+ continue;
+ }
+ print "<li>Created database <tt>" . htmlspecialchars( $wgDBname ) . "</tt></li>\n";
}
- print "<li>Created database <tt>" . htmlspecialchars( $wgDBname ) . "</tt></li>\n";
+ $wgDatabase->selectDB( $wgDBname );
}
- $wgDatabase->selectDB( $wgDBname );
if( $wgDatabase->tableExists( "cur" ) || $wgDatabase->tableExists( "revision" ) ) {
print "<li>There are already MediaWiki tables in this database. Checking if updates are needed...</li>\n";
} else {
# FIXME: Check for errors
print "<li>Creating tables...";
- dbsource( "../maintenance/tables.sql", $wgDatabase );
- dbsource( "../maintenance/interwiki.sql", $wgDatabase );
+ if ($conf->DBtype == 'mysql') {
+ dbsource( "../maintenance/tables.sql", $wgDatabase );
+ dbsource( "../maintenance/interwiki.sql", $wgDatabase );
+ } else {
+ dbsource( "../maintenance/oracle/tables.sql", $wgDatabase );
+ dbsource( "../maintenance/oracle/interwiki.sql", $wgDatabase );
+ }
+
print " done.</li>\n";
print "<li>Initializing data...";
<h2>Database config</h2>
<dl class="setup">
+ <dd>
+ <label class='column'>Database type</label>
+ <div>Select the database server software:</div>
+ <ul class='plain'>
+ <?php
+ aField( $conf, "DBtype", "MySQL", "radio", "mysql");
+ aField( $conf, "DBtype", "Oracle", "radio", "oracle" );
+ ?>
+ </ul>
+ </dd>
+
<dd><?php
- aField( $conf, "DBserver", "MySQL server" );
+ aField( $conf, "DBserver", "SQL server host" );
?></dd>
<dt>
If your database server isn't on your web server, enter the name
- or IP address here.
+ or IP address here. MySQL only.
</dt>
<dd><?php
aField( $conf, "DBname", "Database name" );
?></dd>
+ <dt>
+ If using Oracle, set this to your connection identifier.
+ </dt>
<dd><?php
aField( $conf, "DBuser", "DB username" );
?></dd>
\$wgDBuser = \"{$slconf['DBuser']}\";
\$wgDBpassword = \"{$slconf['DBpassword']}\";
\$wgDBprefix = \"{$slconf['DBprefix']}\";
+\$wgDBtype = \"{$slconf['DBtype']}\";
# If you're on MySQL 3.x, this next line must be FALSE:
\$wgDBmysql4 = {$conf->DBmysql4};
return false;
}
+function get_db_version() {
+ global $wgDatabase, $conf;
+ if ($conf->DBtype == 'mysql')
+ return mysql_get_server_info( $wgDatabase->mConn );
+ else if ($conf->DBtype == 'oracle')
+ return oci_server_version($wgDatabase->mConn);
+}
+
# Test a memcached server
function testMemcachedServer( $server ) {
$hostport = explode(":", $server);
* Get the database which should be used for reads
*/
function &getDB() {
+ $ret = wfGetDB( DB_MASTER );
+ return $ret;
#if ( $this->mForUpdate ) {
$ret =& wfGetDB( DB_MASTER );
#} else {
function getTimestamp() {
$this->loadLastEdit();
- return $this->mTimestamp;
+ return wfTimestamp(TS_MW, $this->mTimestamp);
}
function getUser() {
$tbtext = "";
while ($o = $dbr->fetchObject($tbs)) {
- $rmvtext = "";
+ $rmvtxt = "";
if ($wgUser->isSysop()) {
$delurl = $this->mTitle->getFullURL("action=deletetrackback&tbid="
. $o->tb_id . "&token=" . $wgUser->editToken());
# An extra check against threads stepping on each other
$conditions['page_latest'] = $lastRevision;
}
+
$text = $revision->getText();
$dbw->update( 'page',
array( /* SET */
'page_latest' => $revision->getId(),
'page_touched' => $dbw->timestamp(),
'page_is_new' => ($lastRevision === 0) ? 1 : 0,
- 'page_is_redirect' => Article::isRedirect( $text ),
+ 'page_is_redirect' => Article::isRedirect( $text ) ? 1 : 0,
'page_len' => strlen( $text ),
),
$conditions,
'page_latest=rev_id' ),
$fname );
if( $row ) {
- if( $row->rev_timestamp >= $revision->getTimestamp() ) {
+ if( wfTimestamp(TS_MW, $row->rev_timestamp) >= $revision->getTimestamp() ) {
wfProfileOut( $fname );
return false;
}
#
# Copyright (C) 2003-2004 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @package MediaWiki
*/
-
+
/**
* Simple generic object store
*
*/
class BagOStuff {
var $debugmode;
-
+
function BagOStuff() {
$this->set_debug( false );
}
-
+
function set_debug($bool) {
$this->debugmode = $bool;
}
-
+
/* *** THE GUTS OF THE OPERATION *** */
/* Override these with functional things in subclasses */
-
+
function get($key) {
/* stub */
return false;
/* stub */
return false;
}
-
+
function delete($key, $time=0) {
/* stub */
return false;
}
-
+
function lock($key, $timeout = 0) {
/* stub */
return true;
/* stub */
return true;
}
-
+
/* *** Emulated functions *** */
/* Better performance can likely be got with custom written versions */
function get_multi($keys) {
$out[$key] = $this->get($key);
return $out;
}
-
+
function set_multi($hash, $exptime=0) {
foreach($hash as $key => $value)
$this->set($key, $value, $exptime);
}
-
+
function add($key, $value, $exptime=0) {
if( $this->get($key) == false ) {
$this->set($key, $value, $exptime);
return true;
}
}
-
+
function add_multi($hash, $exptime=0) {
foreach($hash as $key => $value)
$this->add($key, $value, $exptime);
foreach($keys as $key)
$this->delete($key, $time);
}
-
+
function replace($key, $value, $exptime=0) {
if( $this->get($key) !== false )
$this->set($key, $value, $exptime);
}
-
+
function incr($key, $value=1) {
if ( !$this->lock($key) ) {
return false;
$this->unlock($key);
return $n;
}
-
+
function decr($key, $value=1) {
if ( !$this->lock($key) ) {
return false;
$this->unlock($key);
return $m;
}
-
+
function _debug($text) {
if($this->debugmode)
wfDebug("BagOStuff debug: $text\n");
persist between program runs.
*/
var $bag;
-
+
function HashBagOStuff() {
$this->bag = array();
}
-
+
function _expire($key) {
$et = $this->bag[$key][1];
if(($et == 0) || ($et > time()))
$this->delete($key);
return true;
}
-
+
function get($key) {
if(!$this->bag[$key])
return false;
return false;
return $this->bag[$key][0];
}
-
+
function set($key,$value,$exptime=0) {
if(($exptime != 0) && ($exptime < 3600*24*30))
$exptime = time() + $exptime;
$this->bag[$key] = array( $value, $exptime );
}
-
+
function delete($key,$time=0) {
if(!$this->bag[$key])
return false;
function SqlBagOStuff($tablename = 'objectcache') {
$this->table = $tablename;
}
-
+
function get($key) {
/* expire old entries if any */
$this->garbageCollect();
-
+
$res = $this->_query(
"SELECT value,exptime FROM $0 WHERE keyname='$1'", $key);
if(!$res) {
}
return false;
}
-
+
function set($key,$value,$exptime=0) {
$exptime = intval($exptime);
if($exptime < 0) $exptime = 0;
$exp = $this->_fromunixtime($exptime);
}
$this->delete( $key );
- $this->_query(
- "INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2','$exp')",
- $key, $this->_serialize($value));
+ $this->_doinsert($this->getTableName(), array(
+ 'keyname' => $key,
+ 'value' => $this->_blobencode($this->_serialize($value)),
+ 'exptime' => $exp
+ ));
return true; /* ? */
}
-
+
function delete($key,$time=0) {
$this->_query(
"DELETE FROM $0 WHERE keyname='$1'", $key );
return true; /* ? */
}
-
+
function getTableName() {
return $this->table;
}
-
+
function _query($sql) {
$reps = func_get_args();
$reps[0] = $this->getTableName();
for($i=0;$i<count($reps);$i++) {
$sql = str_replace(
'$' . $i,
- $this->_strencode($reps[$i]),
+ $i > 0 ? $this->_strencode($reps[$i]) : $reps[$i],
$sql);
}
$res = $this->_doquery($sql);
}
return $res;
}
-
+
function _strencode($str) {
/* Protect strings in SQL */
return str_replace( "'", "''", $str );
}
-
+ function _blobencode($str) {
+ return $str;
+ }
+ function _doinsert($table, $vals) {
+ die( 'abstract function SqlBagOStuff::_doinsert() must be defined' );
+ }
function _doquery($sql) {
die( 'abstract function SqlBagOStuff::_doquery() must be defined' );
}
-
+
function _fetchrow($res) {
die( 'abstract function SqlBagOStuff::_fetchrow() must be defined' );
}
-
+
function _freeresult($result) {
/* stub */
return false;
}
-
+
function _dberror($result) {
/* stub */
return 'unknown error';
}
-
+
function _maxdatetime() {
die( 'abstract function SqlBagOStuff::_maxdatetime() must be defined' );
}
-
+
function _fromunixtime() {
die( 'abstract function SqlBagOStuff::_fromunixtime() must be defined' );
}
-
+
function garbageCollect() {
/* Ignore 99% of requests */
if ( !mt_rand( 0, 100 ) ) {
}
}
}
-
+
function expireall() {
/* Remove any items that have expired */
$now = $this->_fromunixtime( time() );
- $this->_query( "DELETE FROM $0 WHERE exptime<'$now'" );
+ $this->_query( "DELETE FROM $0 WHERE exptime < '$now'" );
}
-
+
function deleteall() {
/* Clear *all* items from cache table */
$this->_query( "DELETE FROM $0" );
}
-
+
/**
* Serialize an object and, if possible, compress the representation.
* On typical message and page data, this can provide a 3X decrease
return $serial;
}
}
-
+
/**
* Unserialize and, if necessary, decompress an object.
* @param string $serial
$serial = $decomp;
}
}
- return unserialize( $serial );
+ wfdebug("serial: [$serial]\n");
+ $ret = unserialize( $serial );
+ return $ret;
}
}
function _doquery($sql) {
$dbw =& wfGetDB( DB_MASTER );
- return $dbw->query($sql, 'MediaWikiBagOStuff:_doquery');
+ return $dbw->query($sql, 'MediaWikiBagOStuff::_doquery');
+ }
+ function _doinsert($t, $v) {
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->insert($t, $v, 'MediaWikiBagOStuff::_doinsert');
}
function _fetchobject($result) {
$dbw =& wfGetDB( DB_MASTER );
return $dbw->lastError();
}
function _maxdatetime() {
- return '9999-12-31 12:59:59';
+ $dbw =& wfGetDB(DB_MASTER);
+ return $dbw->timestamp('9999-12-31 12:59:59');
}
function _fromunixtime($ts) {
- return gmdate( 'Y-m-d H:i:s', $ts );
+ $dbw =& wfGetDB(DB_MASTER);
+ return $dbw->timestamp($ts);
}
function _strencode($s) {
$dbw =& wfGetDB( DB_MASTER );
return $dbw->strencode($s);
}
+ function _blobencode($s) {
+ $dbw =& wfGetDB( DB_MASTER );
+ return $dbw->encodeBlob($s);
+ }
function getTableName() {
if ( !$this->tableInitialised ) {
$dbw =& wfGetDB( DB_MASTER );
}
/**
- * This is a wrapper for Turck MMCache's shared memory functions.
- *
- * You can store objects with mmcache_put() and mmcache_get(), but Turck seems
- * to use a weird custom serializer that randomly segfaults. So we wrap calls
+ * This is a wrapper for Turck MMCache's shared memory functions.
+ *
+ * You can store objects with mmcache_put() and mmcache_get(), but Turck seems
+ * to use a weird custom serializer that randomly segfaults. So we wrap calls
* with serialize()/unserialize().
- *
+ *
* The thing I noticed about the Turck serialized data was that unlike ordinary
- * serialize(), it contained the names of methods, and judging by the amount of
- * binary data, perhaps even the bytecode of the methods themselves. It may be
- * that Turck's serializer is faster, so a possible future extension would be
+ * serialize(), it contained the names of methods, and judging by the amount of
+ * binary data, perhaps even the bytecode of the methods themselves. It may be
+ * that Turck's serializer is faster, so a possible future extension would be
* to use it for arrays but not for objects.
*
* @package MediaWiki
mmcache_put( $key, serialize( $value ), $exptime );
return true;
}
-
+
function delete($key, $time=0) {
mmcache_rm( $key );
return true;
mmcache_unlock( $key );
return true;
}
-}
+}
/**
- * This is a wrapper for eAccelerator's shared memory functions.
- *
+ * This is a wrapper for eAccelerator's shared memory functions.
+ *
* This is basically identical to the Turck MMCache version,
* mostly because eAccelerator is based on Turck MMCache.
*
eaccelerator_put( $key, serialize( $value ), $exptime );
return true;
}
-
+
function delete($key, $time=0) {
eaccelerator_rm( $key );
return true;
eaccelerator_unlock( $key );
return true;
}
-}
+}
?>
/**
* The block class
- * All the functions in this class assume the object is either explicitly
+ * All the functions in this class assume the object is either explicitly
* loaded or filled. It is not load-on-demand. There are no accessors.
- *
+ *
* To use delete(), you only need to fill $mAddress
* Globals used: $wgBlockCache, $wgAutoblockExpiry
*
{
/* public*/ var $mAddress, $mUser, $mBy, $mReason, $mTimestamp, $mAuto, $mId, $mExpiry;
/* private */ var $mNetworkBits, $mIntegerAddr, $mForUpdate;
-
- function Block( $address = '', $user = '', $by = 0, $reason = '',
- $timestamp = '' , $auto = 0, $expiry = '' )
+
+ function Block( $address = '', $user = '', $by = 0, $reason = '',
+ $timestamp = '' , $auto = 0, $expiry = '' )
{
$this->mAddress = $address;
$this->mUser = $user;
} else {
$this->mExpiry = wfTimestamp( TS_MW, $expiry );
}
-
+
$this->mForUpdate = false;
$this->initialiseRange();
}
-
- /*static*/ function newFromDB( $address, $user = 0, $killExpired = true )
+
+ /*static*/ function newFromDB( $address, $user = 0, $killExpired = true )
{
$ban = new Block();
$ban->load( $address, $user, $killExpired );
return $ban;
}
-
- function clear()
+
+ function clear()
{
$mAddress = $mReason = $mTimestamp = '';
$mUser = $mBy = 0;
/**
* Get a ban from the DB, with either the given address or the given username
*/
- function load( $address = '', $user = 0, $killExpired = true )
+ function load( $address = '', $user = 0, $killExpired = true )
{
global $wgDBmysql4, $wgAntiLockFlags;
$fname = 'Block::load';
} else {
# If there are options, a UNION can not be used, use one
# SELECT instead. Will do a full table scan.
- $sql = "SELECT * FROM $ipblocks WHERE (ipb_address='" . $db->strencode( $address ) .
+ $sql = "SELECT * FROM $ipblocks WHERE (ipb_address='" . $db->strencode( $address ) .
"' OR ipb_user={$user}) $options";
}
}
}
} while ( $killed && $row );
-
+
# If there were any left after the killing finished, return true
if ( !$row ) {
$ret = false;
$db->freeResult( $res );
return $ret;
}
-
- function initFromRow( $row )
+
+ function initFromRow( $row )
{
$this->mAddress = $row->ipb_address;
$this->mReason = $row->ipb_reason;
$row->ipb_expiry;
$this->initialiseRange();
- }
+ }
function initialiseRange()
{
$this->mIntegerAddr = false;
}
}
-
+
/**
* Callback with a Block object for every block
*/
- /*static*/ function enumBlocks( $callback, $tag, $flags = 0 )
+ /*static*/ function enumBlocks( $callback, $tag, $flags = 0 )
{
global $wgAntiLockFlags;
} else {
$db =& wfGetDB( DB_SLAVE );
$options = '';
- }
+ }
$ipblocks = $db->tableName( 'ipblocks' );
-
+
$sql = "SELECT * FROM $ipblocks ORDER BY ipb_timestamp DESC $options";
$res = $db->query( $sql, 'Block::enumBans' );
wfFreeResult( $res );
}
- function delete()
+ function delete()
{
$fname = 'Block::delete';
if (wfReadOnly()) {
$this->clearCache();
}
- function insert()
+ function insert()
{
wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
$dbw =& wfGetDB( DB_MASTER );
+ $ipb_id = $dbw->nextSequenceValue('ipblocks_ipb_id_val');
$dbw->insert( 'ipblocks',
array(
+ 'ipb_id' => $ipb_id,
'ipb_address' => $this->mAddress,
'ipb_user' => $this->mUser,
'ipb_by' => $this->mBy,
'ipb_expiry' => $this->mExpiry ?
$dbw->timestamp($this->mExpiry) :
$this->mExpiry,
- ), 'Block::insert'
+ ), 'Block::insert'
);
$this->clearCache();
}
- function deleteIfExpired()
+ function deleteIfExpired()
{
if ( $this->isExpired() ) {
wfDebug( "Block::deleteIfExpired() -- deleting\n" );
}
}
- function isExpired()
- {
+ function isExpired()
+ {
wfDebug( "Block::isExpired() checking current " . wfTimestampNow() . " vs $this->mExpiry\n" );
if ( !$this->mExpiry ) {
return false;
}
}
- function isValid()
+ function isValid()
{
return $this->mAddress != '';
}
-
- function updateTimestamp()
+
+ function updateTimestamp()
{
if ( $this->mAuto ) {
$this->mTimestamp = wfTimestamp();
$this->mExpiry = Block::getAutoblockExpiry( $this->mTimestamp );
$dbw =& wfGetDB( DB_MASTER );
- $dbw->update( 'ipblocks',
- array( /* SET */
+ $dbw->update( 'ipblocks',
+ array( /* SET */
'ipb_timestamp' => $dbw->timestamp($this->mTimestamp),
'ipb_expiry' => $dbw->timestamp($this->mExpiry),
), array( /* WHERE */
'ipb_address' => $this->mAddress
- ), 'Block::updateTimestamp'
+ ), 'Block::updateTimestamp'
);
-
+
$this->clearCache();
}
}
$wgBlockCache->loadFromDB();
}
}
-
+
function getIntegerAddr()
{
return $this->mIntegerAddr;
}
-
+
function getNetworkBits()
{
return $this->mNetworkBits;
*
* @package MediaWiki
*/
-
+
if( !defined( 'MEDIAWIKI' ) )
die();
require_once('ImageGallery.php');
/**
- * @package MediaWiki
+ * @package MediaWiki
*/
class CategoryPage extends Article {
}
Article::view();
-
+
# If the article we've just shown is in the "Image" namespace,
# follow it with the history list and link list for the image
# it describes.
function openShowCategory() {
# For overloading
}
-
+
# generate a list of subcategories and pages for a category
# depending on wfMsg("usenewcategorypage") it either calls the new
# or the old code. The new code will not work properly for some
$pageCondition = 'cl_sortkey < ' . $dbr->addQuotes( $until );
$flip = true;
} else {
- $pageCondition = '1';
+ $pageCondition = '1 = 1';
$flip = false;
}
$limit = 200;
$fname,
array( 'ORDER BY' => $flip ? 'cl_sortkey DESC' : 'cl_sortkey',
'LIMIT' => $limit + 1 ) );
-
+
$sk =& $wgUser->getSkin();
$r = "<br style=\"clear:both;\"/>\n";
$count = 0;
$nextPage = $x->cl_sortkey;
break;
}
-
+
$title = Title::makeTitle( $x->page_namespace, $x->page_title );
-
+
if( $title->getNamespace() == NS_CATEGORY ) {
// Subcategory; strip the 'Category' namespace from the link text.
array_push( $children, $sk->makeKnownLinkObj( $title, $wgContLang->convertHtml( $title->getText() ) ) );
-
+
// If there's a link from Category:A to Category:B, the sortkey of the resulting
// entry in the categorylinks table is Category:A, not A, which it SHOULD be.
// Workaround: If sortkey == "Category:".$title, than use $title for sorting,
$articles = array_reverse( $articles );
$articles_start_char = array_reverse( $articles_start_char );
}
-
+
if( $until != '' ) {
$r .= $this->pagingLinks( $this->mTitle, $nextPage, $until, $limit );
} elseif( $nextPage != '' || $from != '' ) {
$r .= $this->pagingLinks( $this->mTitle, $from, $nextPage, $limit );
}
-
+
# Don't show subcategories section if there are none.
if( count( $children ) > 0 ) {
# Showing subcategories
}
return '';
}
-
+
/**
* Format a list of articles chunked by letter in a three-column
* list, ordered vertically.
// get and display header
$r = '<table width="100%"><tr valign="top">';
- $prev_start_char = 'none';
+ $prev_start_char = 'none';
// loop through the chunks
for($startChunk = 0, $endChunk = $chunk, $chunkIndex = 0;
$r .= '</tr></table>';
return $r;
}
-
+
/**
* Format a list of articles chunked by letter in a bullet list.
* @param array $articles
$r .= '</ul>';
return $r;
}
-
+
/**
* @param Title $title
* @param string $first
global $wgUser, $wgLang;
$sk =& $wgUser->getSkin();
$limitText = $wgLang->formatNum( $limit );
-
+
$prevLink = htmlspecialchars( wfMsg( 'prevn', $limitText ) );
if( $first != '' ) {
$prevLink = $sk->makeLinkObj( $title, $prevLink,
$nextLink = $sk->makeLinkObj( $title, $nextLink,
wfArrayToCGI( $query + array( 'from' => $last ) ) );
}
-
+
return "($prevLink) ($nextLink)";
}
}
<?php
/**
- * This file deals with MySQL interface functions
+ * This file deals with MySQL interface functions
* and query specifics/optimisations
* @package MediaWiki
*/
/** Maximum time to wait before retry */
define( 'DEADLOCK_DELAY_MAX', 1500000 );
+class DBObject {
+ var $mData;
+
+ function DBObject($data) {
+ $this->mData = $data;
+ }
+
+ function isLOB() {
+ return false;
+ }
+
+ function data() {
+ return $this->mData;
+ }
+};
+
/**
* Database abstraction object
* @package MediaWiki
* @access private
*/
var $mLastQuery = '';
-
+
var $mServer, $mUser, $mPassword, $mConn, $mDBname;
var $mOut, $mOpened = false;
-
- var $mFailFunction;
+
+ var $mFailFunction;
var $mTablePrefix;
var $mFlags;
var $mTrxLevel = 0;
# Accessors
#------------------------------------------------------------------------------
# These optionally set a variable and return the previous state
-
+
/**
* Fail function, takes a Database as a parameter
* Set to false for default, 1 for ignore errors
*/
- function failFunction( $function = NULL ) {
- return wfSetVar( $this->mFailFunction, $function );
+ function failFunction( $function = NULL ) {
+ return wfSetVar( $this->mFailFunction, $function );
}
-
+
/**
* Output page, used for reporting errors
* FALSE means discard output
*/
- function &setOutputPage( &$out ) {
- $this->mOut =& $out;
+ function &setOutputPage( &$out ) {
+ $this->mOut =& $out;
}
-
+
/**
* Boolean, controls output of large amounts of debug information
*/
- function debug( $debug = NULL ) {
- return wfSetBit( $this->mFlags, DBO_DEBUG, $debug );
+ function debug( $debug = NULL ) {
+ return wfSetBit( $this->mFlags, DBO_DEBUG, $debug );
}
-
+
/**
* Turns buffering of SQL result sets on (true) or off (false).
* Default is "on" and it should not be changed without good reasons.
if ( is_null( $buffer ) ) {
return !(bool)( $this->mFlags & DBO_NOBUFFER );
} else {
- return !wfSetBit( $this->mFlags, DBO_NOBUFFER, !$buffer );
+ return !wfSetBit( $this->mFlags, DBO_NOBUFFER, !$buffer );
}
}
* code should use wfLastErrno() and wfLastError() to handle the
* situation as appropriate.
*/
- function ignoreErrors( $ignoreErrors = NULL ) {
- return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors );
+ function ignoreErrors( $ignoreErrors = NULL ) {
+ return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors );
}
-
+
/**
* The current depth of nested transactions
* @param integer $level
return wfSetVar( $this->mTrxLevel, $level );
}
- /**
+ /**
* Number of errors logged, only useful when errors are ignored
*/
function errorCount( $count = NULL ) {
* @param string $password database user password
* @param string $dbname database name
*/
-
+
/**
* @param failFunction
* @param $flags
* @param string $tablePrefix Database table prefixes. By default use the prefix gave in LocalSettings.php
*/
- function Database( $server = false, $user = false, $password = false, $dbName = false,
+ function Database( $server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' ) {
-
+
global $wgOut, $wgDBprefix, $wgCommandLineMode;
# Can't get a reference if it hasn't been set yet
if ( !isset( $wgOut ) ) {
$this->mFailFunction = $failFunction;
$this->mFlags = $flags;
-
+
if ( $this->mFlags & DBO_DEFAULT ) {
if ( $wgCommandLineMode ) {
$this->mFlags &= ~DBO_TRX;
$this->mFlags |= DBO_PERSISTENT;
$this->mFlags &= ~DBO_TRX;
}*/
-
+
/** Get the default table prefix*/
if ( $tablePrefix == 'get from global' ) {
$this->mTablePrefix = $wgDBprefix;
$this->open( $server, $user, $password, $dbName );
}
}
-
+
/**
* @static
* @param failFunction
* @param $flags
*/
- function newFromParams( $server, $user, $password, $dbName,
+ function newFromParams( $server, $user, $password, $dbName,
$failFunction = false, $flags = 0 )
{
return new Database( $server, $user, $password, $dbName, $failFunction, $flags );
}
-
+
/**
* Usually aborts on failure
* If the failFunction is set to a non-zero integer, returns success
if ( !function_exists( 'mysql_connect' ) ) {
die( "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" );
}
-
+
$this->close();
$this->mServer = $server;
$this->mUser = $user;
$this->mPassword = $password;
$this->mDBname = $dbName;
-
+
$success = false;
-
+
if ( $this->mFlags & DBO_PERSISTENT ) {
@/**/$this->mConn = mysql_pconnect( $server, $user, $password );
} else {
}
} else {
wfDebug( "DB connection error\n" );
- wfDebug( "Server: $server, User: $user, Password: " .
+ wfDebug( "Server: $server, User: $user, Password: " .
substr( $password, 0, 3 ) . "..., error: " . mysql_error() . "\n" );
$success = false;
}
# Delay USE query
$success = (bool)$this->mConn;
}
-
+
if ( !$success ) {
$this->reportConnectionError();
$this->close();
return $success;
}
/**#@-*/
-
+
/**
* Closes a database connection.
* if it is open : commits any open transactions
return true;
}
}
-
+
/**
* @access private
* @param string $msg error message ?
if ( $this->mFailFunction ) {
if ( !is_int( $this->mFailFunction ) ) {
$ff = $this->mFailFunction;
- $ff( $this, mysql_error() );
+ $ff( $this, $this->lastError() );
}
} else {
wfEmergencyAbort( $this, mysql_error() );
}
}
-
+
/**
* Usually aborts on failure
* If errors are explicitly ignored, returns success
*/
function query( $sql, $fname = '', $tempIgnore = false ) {
global $wgProfiling, $wgCommandLineMode;
-
+
if ( wfReadOnly() ) {
- # This is a quick check for the most common kinds of write query used
- # in MediaWiki, to provide extra safety in addition to UI-level checks.
- # It is not intended to prevent every conceivable write query, or even
+ # This is a quick check for the most common kinds of write query used
+ # in MediaWiki, to provide extra safety in addition to UI-level checks.
+ # It is not intended to prevent every conceivable write query, or even
# to handle such queries gracefully.
if ( preg_match( '/^(update|insert|replace|delete)/i', $sql ) ) {
wfDebug( "Write query from $fname blocked\n" );
wfProfileIn( 'Database::query' );
wfProfileIn( $profName );
}
-
+
$this->mLastQuery = $sql;
-
+
# Add a comment for easy SHOW PROCESSLIST interpretation
if ( $fname ) {
$commentedSql = "/* $fname */ $sql";
$sqlx = strtr( $sqlx, "\t\n", ' ' );
wfDebug( "SQL: $sqlx\n" );
}
-
+
# Do the query and handle errors
$ret = $this->doQuery( $commentedSql );
if ( false === $ret ) {
$this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
}
-
+
if ( $wgProfiling ) {
wfProfileOut( $profName );
wfProfileOut( 'Database::query' );
}
return $ret;
}
-
+
/**
* The DBMS-dependent part of query()
* @param string $sql SQL query.
$ret = mysql_query( $sql, $this->mConn );
} else {
$ret = mysql_unbuffered_query( $sql, $this->mConn );
- }
+ }
return $ret;
}
"Query: $sql\n" .
"Function: $fname\n" .
"Error: $errno $error\n";
- if ( !$wgCommandLineMode ) {
+ if ( !$wgCommandLineMode ) {
$message = nl2br( $message );
}
wfDebugDieBacktrace( $message );
} else {
// this calls wfAbruptExit()
- $this->mOut->databaseError( $fname, $sql, $error, $errno );
+ $this->mOut->databaseError( $fname, $sql, $error, $errno );
}
}
$this->ignoreErrors( $ignore );
the bits later. */
return array( 'query' => $sql, 'func' => $func );
}
-
+
function freePrepared( $prepared ) {
/* No-op for MySQL */
}
-
+
/**
* Execute a prepared query with the various arguments
* @param string $prepared the prepared sql
$sql = $this->fillPrepared( $prepared['query'], $args );
return $this->query( $sql, $prepared['func'] );
}
-
+
/**
* Prepare & execute an SQL statement, quoting and inserting arguments
* in the appropriate places.
$this->freePrepared( $prepared );
return $retval;
}
-
+
/**
* For faking prepared SQL statements on DBs that don't support
* it directly.
return preg_replace_callback( '/(\\\\[?!&]|[?!&])/',
array( &$this, 'fillPreparedArg' ), $preparedQuery );
}
-
+
/**
* preg_callback func for fillPrepared()
* The arguments should be in $this->preparedArgs and must not be touched
* while we're doing this.
- *
+ *
* @param array $matches
* @return string
* @access private
wfDebugDieBacktrace( 'Received invalid match. This should never happen!' );
}
}
-
+
/**#@+
* @param mixed $res A SQL result
*/
wfDebugDieBacktrace( "Unable to free MySQL result\n" );
}
}
-
+
/**
* Fetch the next row from the given result object, in object form
*/
wfDebugDieBacktrace( 'Error in fetchRow(): ' . htmlspecialchars( mysql_error() ) );
}
return $row;
- }
+ }
/**
* Get the number of rows in a result object
*/
function numRows( $res ) {
- @/**/$n = mysql_num_rows( $res );
+ @/**/$n = mysql_num_rows( $res );
if( mysql_errno() ) {
wfDebugDieBacktrace( 'Error in numRows(): ' . htmlspecialchars( mysql_error() ) );
}
return $n;
}
-
+
/**
* Get the number of fields in a result object
* See documentation for mysql_num_fields()
* $id = $dbw->insertId();
*/
function insertId() { return mysql_insert_id( $this->mConn ); }
-
+
/**
* Change the position of the cursor in a result object
* See mysql_data_seek()
*/
function dataSeek( $res, $row ) { return mysql_data_seek( $res, $row ); }
-
+
/**
* Get the last error number
* See mysql_errno()
*/
- function lastErrno() {
+ function lastErrno() {
if ( $this->mConn ) {
- return mysql_errno( $this->mConn );
+ return mysql_errno( $this->mConn );
} else {
return mysql_errno();
}
}
-
+
/**
* Get a description of the last error
* See mysql_error() for more details
*/
- function lastError() {
+ function lastError() {
if ( $this->mConn ) {
- $error = mysql_error( $this->mConn );
+ $error = mysql_error( $this->mConn );
} else {
$error = mysql_error();
}
$error .= ' (' . $this->mServer . ')';
}
return $error;
- }
+ }
/**
* Get the number of rows affected by the last write query
* See mysql_affected_rows() for more details
* Usually aborts on failure
* If errors are explicitly ignored, returns success
*
- * This function exists for historical reasons, Database::update() has a more standard
+ * This function exists for historical reasons, Database::update() has a more standard
* calling convention and feature set
*/
function set( $table, $var, $value, $cond, $fname = 'Database::set' )
$this->strencode( $value ) . "' WHERE ($cond)";
return (bool)$this->query( $sql, DB_MASTER, $fname );
}
-
+
/**
* Simple SELECT wrapper, returns a single field, input must be encoded
* Usually aborts on failure
return false;
}
}
-
+
/**
* Returns an optional USE INDEX clause to go after the table, and a
* string to go at the end of the query
}
if ( isset( $options['ORDER BY'] ) ) {
$tailOpts .= " ORDER BY {$options['ORDER BY']}";
- }
- if ( isset( $options['LIMIT'] ) ) {
- $tailOpts .= " LIMIT {$options['LIMIT']}";
}
if ( is_numeric( array_search( 'FOR UPDATE', $options ) ) ) {
$tailOpts .= ' FOR UPDATE';
}
-
+
if ( is_numeric( array_search( 'LOCK IN SHARE MODE', $options ) ) ) {
$tailOpts .= ' LOCK IN SHARE MODE';
}
if( is_array( $vars ) ) {
$vars = implode( ',', $vars );
}
+ if( !is_array( $options ) ) {
+ $options = array( $options );
+ }
if( is_array( $table ) ) {
$from = ' FROM ' . implode( ',', array_map( array( &$this, 'tableName' ), $table ) );
} elseif ($table!='') {
$from = '';
}
- list( $useIndex, $tailOpts ) = $this->makeSelectOptions( (array)$options );
-
+ list( $useIndex, $tailOpts ) = $this->makeSelectOptions( array($options) );
+
if( !empty( $conds ) ) {
if ( is_array( $conds ) ) {
$conds = $this->makeList( $conds, LIST_AND );
} else {
$sql = "SELECT $vars $from $useIndex $tailOpts";
}
+ if (isset($options['LIMIT'])) {
+ $sql = $this->limitResult($sql, $options['LIMIT'], false);
+ }
return $this->query( $sql, $fname );
}
/**
* Single row SELECT wrapper
* Aborts or returns FALSE on error
- *
+ *
* $vars: the selected variables
- * $conds: a condition map, terms are ANDed together.
+ * $conds: a condition map, terms are ANDed together.
* Items with numeric keys are taken to be literal conditions
* Takes an array of selected variables, and a condition map, which is ANDed
* e.g: selectRow( "page", array( "page_id" ), array( "page_namespace" =>
function selectRow( $table, $vars, $conds, $fname = 'Database::selectRow', $options = array() ) {
$options['LIMIT'] = 1;
$res = $this->select( $table, $vars, $conds, $fname, $options );
- if ( $res === false || !$this->numRows( $res ) ) {
+ if ( $res === false )
+ return false;
+ if ( !$this->numRows($res) ) {
+ $this->freeResult($res);
return false;
}
$obj = $this->fetchObject( $res );
$this->freeResult( $res );
return $obj;
-
+
}
-
+
/**
* Removes most variables from an SQL query and replaces them with X or N for numbers.
* It's only slightly flawed. Don't use for anything important.
* @param string $sql A SQL Query
* @static
*/
- function generalizeSQL( $sql ) {
+ function generalizeSQL( $sql ) {
# This does the same as the regexp below would do, but in such a way
# as to avoid crashing php on some large strings.
# $sql = preg_replace ( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql);
-
+
$sql = str_replace ( "\\\\", '', $sql);
$sql = str_replace ( "\\'", '', $sql);
$sql = str_replace ( "\\\"", '', $sql);
$sql = preg_replace ("/'.*'/s", "'X'", $sql);
$sql = preg_replace ('/".*"/s', "'X'", $sql);
-
+
# All newlines, tabs, etc replaced by single space
$sql = preg_replace ( "/\s+/", ' ', $sql);
-
- # All numbers => N
+
+ # All numbers => N
$sql = preg_replace ('/-?[0-9]+/s', 'N', $sql);
-
+
return $sql;
}
-
+
/**
* Determines whether a field exists in a table
* Usually aborts on failure
if ( !$res ) {
return NULL;
}
-
+
$found = false;
-
+
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->Field == $field ) {
$found = true;
}
return $found;
}
-
+
/**
* Determines whether an index exists
* Usually aborts on failure
return $info !== false;
}
}
-
-
+
+
/**
* Get information about an index into an object
* Returns false if the index does not exist
if ( !$res ) {
return NULL;
}
-
+
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->Key_name == $index ) {
return $row;
}
return false;
}
-
+
/**
* Query whether a given table exists
*/
}
return false;
}
-
+
/**
* mysql_field_type() wrapper
*/
/**
* INSERT wrapper, inserts an array into a table
*
- * $a may be a single associative array, or an array of these with numeric keys, for
+ * $a may be a single associative array, or an array of these with numeric keys, for
* multi-row insert.
*
* Usually aborts on failure
$keys = array_keys( $a );
}
- $sql = 'INSERT ' . implode( ' ', $options ) .
+ $sql = 'INSERT ' . implode( ' ', $options ) .
" INTO $table (" . implode( ',', $keys ) . ') VALUES ';
if ( $multi ) {
}
$this->query( $sql, $fname );
}
-
+
/**
* Makes a wfStrencoded list from an array
* $mode: LIST_COMMA - comma separated, no field names
}
return $list;
}
-
+
/**
* Change the current database
*/
/**
* Format a table name ready for use in constructing an SQL query
- *
- * This does two important things: it quotes table names which as necessary,
+ *
+ * This does two important things: it quotes table names which as necessary,
* and it adds a table prefix if there is one.
- *
- * All functions of this object which require a table name call this function
+ *
+ * All functions of this object which require a table name call this function
* themselves. Pass the canonical name to such functions. This is only needed
- * when calling query() directly.
+ * when calling query() directly.
*
* @param string $name database table name
*/
# Standard quoting
$name = "`$name`";
}
- }
+ }
return $name;
}
*
* Example:
* extract($dbr->tableNames('user','watchlist'));
- * $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
+ * $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
* WHERE wl_user=user_id AND wl_user=$nameWithQuotes";
*/
function tableNames() {
}
return $retVal;
}
-
+
/**
* Wrapper for addslashes()
* @param string $s String to be slashed.
# _are_ strings such as article titles and string->number->string
# conversion is not 1:1.
return "'" . $this->strencode( $s ) . "'";
- }
+ }
}
-
+
/**
* Returns an appropriately quoted sequence value for inserting a new row.
* MySQL has autoincrement fields, so this is just NULL. But the PostgreSQL
* REPLACE query wrapper
* PostgreSQL simulates this with a DELETE followed by INSERT
* $row is the row to insert, an associative array
- * $uniqueIndexes is an array of indexes. Each element may be either a
+ * $uniqueIndexes is an array of indexes. Each element may be either a
* field name or an array of field names
- *
- * 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
+ *
+ * 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
*
* @todo migrate comment to phodocumentor format
* DELETE where the condition is a join
* MySQL does this with a multi-table DELETE syntax, PostgreSQL does it with sub-selects
*
- * For safety, an empty $conds will not delete everything. If you want to delete all rows where the
+ * For safety, an empty $conds will not delete everything. If you want to delete all rows where the
* join condition matches, set $conds='*'
*
* DO NOT put the join condition in $conds
if ( $conds != '*' ) {
$sql .= ' AND ' . $this->makeList( $conds, LIST_AND );
}
-
+
return $this->query( $sql, $fname );
}
$destTable = $this->tableName( $destTable );
if( is_array( $srcTable ) ) {
$srcTable = implode( ',', array_map( array( &$this, 'tableName' ), $srcTable ) );
- } else {
+ } else {
$srcTable = $this->tableName( $srcTable );
}
$sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
- ' SELECT ' . implode( ',', $varMap ) .
+ ' SELECT ' . implode( ',', $varMap ) .
" FROM $srcTable";
if ( $conds != '*' ) {
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
* Construct a LIMIT query with optional offset
* This is used for query pages
*/
- function limitResult($limit,$offset) {
- return ' LIMIT '.(is_numeric($offset)?"{$offset},":"")."{$limit} ";
+ function limitResult($sql, $limit, $offset) {
+ return "$sql LIMIT ".((is_numeric($offset) && $offset != 0)?"{$offset},":"")."{$limit} ";
+ }
+ function limitResultForUpdate($sql, $num) {
+ return $this->limitResult($sql, $num, 0);
}
/**
/**
* Perform a deadlock-prone transaction.
*
- * This function invokes a callback function to perform a set of write
- * queries. If a deadlock occurs during the processing, the transaction
+ * This function invokes a callback function to perform a set of write
+ * queries. If a deadlock occurs during the processing, the transaction
* will be rolled back and the callback function will be called again.
*
- * Usage:
+ * Usage:
* $dbw->deadlockLoop( callback, ... );
*
- * Extra arguments are passed through to the specified callback function.
- *
- * Returns whatever the callback function returned on its successful,
- * iteration, or false on error, for example if the retry limit was
+ * Extra arguments are passed through to the specified callback function.
+ *
+ * Returns whatever the callback function returned on its successful,
+ * iteration, or false on error, for example if the retry limit was
* reached.
*/
function deadlockLoop() {
$myFname = 'Database::deadlockLoop';
-
- $this->query( 'BEGIN', $myFname );
+
+ $this->begin();
$args = func_get_args();
$function = array_shift( $args );
$oldIgnore = $this->ignoreErrors( true );
$error = $this->lastError();
$errno = $this->lastErrno();
$sql = $this->lastQuery();
-
+
if ( $errno ) {
if ( $this->wasDeadlock() ) {
# Retry
function masterPosWait( $file, $pos, $timeout ) {
$fname = 'Database::masterPosWait';
wfProfileIn( $fname );
-
-
+
+
# Commit any open transactions
$this->immediateCommit();
-
+
# Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
$encFile = $this->strencode( $file );
$sql = "SELECT MASTER_POS_WAIT('$encFile', $pos, $timeout)";
return array( false, false );
}
}
-
+
/**
* Get the position of the master from SHOW MASTER STATUS
*/
$this->query( 'BEGIN', $fname );
$this->mTrxLevel = 1;
}
-
+
/**
* Commit transaction, if one is open
*/
function timestamp( $ts=0 ) {
return wfTimestamp(TS_MW,$ts);
}
-
+
/**
* Local database timestamp format or null
*/
return $this->timestamp( $ts );
}
}
-
+
/**
* @todo document
*/
function aggregateValue ($valuedata,$valuename='value') {
return $valuename;
}
-
+
/**
* @return string wikitext of a link to the server software's web site
*/
function getSoftwareLink() {
return "[http://www.mysql.com/ MySQL]";
}
-
+
/**
* @return string Version information from the database
*/
return true;
}
}
-
+
/**
* Get slave lag.
* At the moment, this will only work if the DB user has the PROCESS privilege
*/
function getLag() {
$res = $this->query( 'SHOW PROCESSLIST' );
- # Find slave SQL thread. Assumed to be the second one running, which is a bit
+ # Find slave SQL thread. Assumed to be the second one running, which is a bit
# dubious, but unfortunately there's no easy rigorous way
$slaveThreads = 0;
while ( $row = $this->fetchObject( $res ) ) {
}
return $status;
}
-}
+
+ /**
+ * Return the maximum number of items allowed in a list, or 0 for unlimited.
+ */
+ function maxListLen() {
+ return 0;
+ }
+
+ function encodeBlob($b) {
+ return $b;
+ }
+
+ function notNullTimestamp() {
+ return "!= 0";
+ }
+ function isNullTimestamp() {
+ return "= '0'";
+ }
+}
/**
* Database abstraction object for mySQL
*/
class ResultWrapper {
var $db, $result;
-
+
/**
* @todo document
*/
function numRows() {
return $this->db->numRows( $this->result );
}
-
+
/**
* @todo document
*/
function fetchObject() {
return $this->db->fetchObject( $this->result );
}
-
+
/**
* @todo document
*/
function &fetchRow() {
return $this->db->fetchRow( $this->result );
}
-
+
/**
* @todo document
*/
function wfEmergencyAbort( &$conn, $error ) {
global $wgTitle, $wgUseFileCache, $title, $wgInputEncoding, $wgOutputEncoding;
global $wgSitename, $wgServer;
-
+
# I give up, Brion is right. Getting the message cache to work when there is no DB is tricky.
# Hard coding strings instead.
- $noconnect = 'Sorry! The wiki is experiencing some technical difficulties, and cannot contact the database server. <br />
+ $noconnect = 'Sorry! The wiki is experiencing some technical difficulties, and cannot contact the database server: $1. <br />
$1';
$mainpage = 'Main Page';
$searchdisabled = <<<EOT
} elseif (@/**/$_REQUEST['search']) {
$search = $_REQUEST['search'];
echo $searchdisabled;
- echo str_replace( array( '$1', '$2' ), array( htmlspecialchars( $search ),
+ echo str_replace( array( '$1', '$2' ), array( htmlspecialchars( $search ),
$wgInputEncoding ), $googlesearch );
wfErrorExit();
} else {
if( $cache->isFileCached() ) {
$msg = '<p style="color: red"><b>'.$msg."<br />\n" .
$cachederror . "</b></p>\n";
-
+
$tag = '<div id="article">';
$text = str_replace(
$tag,
$cache->fetchPageText() );
}
}
-
+
echo $text;
wfErrorExit();
}
<?php
/**
* Backwards compatibility wrapper for Database.php
- *
+ *
* Note: $wgDatabase has ceased to exist. Destroy all references.
*
* @package MediaWiki
$c =& wfGetDB( $db );
if ( $c !== false ) {
return $c->query( $sql, $fname );
- } else {
+ } else {
return false;
}
}
$ret =& $wgLoadBalancer->getConnection( $db, true, $groups );
return $ret;
}
-
+
/**
* Turns on (false) or off (true) the automatic generation and sending
* of a "we're sorry, but there has been a database error" page on
* Free a database result
* @return bool whether result is sucessful or not
*/
-function wfFreeResult( $res, $dbi = DB_LAST )
-{
+function wfFreeResult( $res, $dbi = DB_LAST )
+{
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- $db->freeResult( $res );
+ $db->freeResult( $res );
return true;
- } else {
+ } else {
return false;
}
}
* Get an object from a database result
* @return object|false object we requested
*/
-function wfFetchObject( $res, $dbi = DB_LAST ) {
+function wfFetchObject( $res, $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->fetchObject( $res, $dbi = DB_LAST );
- } else {
+ return $db->fetchObject( $res, $dbi = DB_LAST );
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->fetchRow ( $res, $dbi = DB_LAST );
- } else {
+ } else {
return false;
}
}
* Get a number of rows from a database result
* @return integer|false number of rows
*/
-function wfNumRows( $res, $dbi = DB_LAST ) {
+function wfNumRows( $res, $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->numRows( $res, $dbi = DB_LAST );
- } else {
+ return $db->numRows( $res, $dbi = DB_LAST );
+ } else {
return false;
}
}
* Get the number of fields from a database result
* @return integer|false number of fields
*/
-function wfNumFields( $res, $dbi = DB_LAST ) {
+function wfNumFields( $res, $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->numFields( $res );
- } else {
+ return $db->numFields( $res );
+ } else {
return false;
}
}
* @param integer $n id of the field
* @return string|false name of field
*/
-function wfFieldName( $res, $n, $dbi = DB_LAST )
-{
+function wfFieldName( $res, $n, $dbi = DB_LAST )
+{
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->fieldName( $res, $n, $dbi = DB_LAST );
- } else {
+ return $db->fieldName( $res, $n, $dbi = DB_LAST );
+ } else {
return false;
}
}
/**
* @todo document function
*/
-function wfInsertId( $dbi = DB_LAST ) {
+function wfInsertId( $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->insertId();
- } else {
+ return $db->insertId();
+ } else {
return false;
}
}
/**
* @todo document function
*/
-function wfDataSeek( $res, $row, $dbi = DB_LAST ) {
+function wfDataSeek( $res, $row, $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->dataSeek( $res, $row );
- } else {
+ return $db->dataSeek( $res, $row );
+ } else {
return false;
}
}
/**
* @todo document function
*/
-function wfLastErrno( $dbi = DB_LAST ) {
+function wfLastErrno( $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->lastErrno();
- } else {
+ return $db->lastErrno();
+ } else {
return false;
}
}
/**
* @todo document function
*/
-function wfLastError( $dbi = DB_LAST ) {
+function wfLastError( $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->lastError();
- } else {
+ return $db->lastError();
+ } else {
return false;
}
}
/**
* @todo document function
*/
-function wfAffectedRows( $dbi = DB_LAST ) {
+function wfAffectedRows( $dbi = DB_LAST ) {
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
- return $db->affectedRows();
- } else {
+ return $db->affectedRows();
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->lastQuery();
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->set( $table, $var, $value, $cond );
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->selectField( $table, $var, $cond );
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->fieldExists( $table, $field );
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->indexExists( $table, $index );
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->insert( $table, $array, $fname );
- } else {
+ } else {
return false;
}
}
$db =& wfGetDB( $dbi );
if ( $db !== false ) {
return $db->getArray( $table, $vars, $conds, $fname );
- } else {
+ } else {
return false;
}
}
--- /dev/null
+<?php
+
+/**
+ * Oracle.
+ *
+ * @package MediaWiki
+ */
+
+/**
+ * Depends on database
+ */
+require_once( 'Database.php' );
+
+class OracleBlob extends DBObject {
+ function isLOB() {
+ return true;
+ }
+ function data() {
+ return $this->mData;
+ }
+};
+
+/**
+ *
+ * @package MediaWiki
+ */
+class DatabaseOracle extends Database {
+ var $mInsertId = NULL;
+ var $mLastResult = NULL;
+ var $mFetchCache = array();
+ var $mFetchID = array();
+ var $mNcols = array();
+ var $mFieldNames = array(), $mFieldTypes = array();
+ var $mAffectedRows = array();
+ var $mErr;
+
+ function DatabaseOracle($server = false, $user = false, $password = false, $dbName = false,
+ $failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
+ {
+ Database::Database( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
+ }
+
+ /* static */ function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
+ $failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
+ {
+ return new DatabaseOracle( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
+ }
+
+ /**
+ * Usually aborts on failure
+ * If the failFunction is set to a non-zero integer, returns success
+ */
+ function open( $server, $user, $password, $dbName ) {
+ if ( !function_exists( 'oci_connect' ) ) {
+ die( "Oracle functions missing, have you compiled PHP with the --with-oci8 option?\n" );
+ }
+ $this->close();
+ $this->mServer = $server;
+ $this->mUser = $user;
+ $this->mPassword = $password;
+ $this->mDBname = $dbName;
+
+ $success = false;
+
+ $hstring="";
+ $this->mConn = oci_new_connect($user, $password, $dbName, "AL32UTF8");
+ if ( $this->mConn === false ) {
+ wfDebug( "DB connection error\n" );
+ wfDebug( "Server: $server, Database: $dbName, User: $user, Password: "
+ . substr( $password, 0, 3 ) . "...\n" );
+ wfDebug( $this->lastError()."\n" );
+ } else {
+ $this->mOpened = true;
+ }
+ return $this->mConn;
+ }
+
+ /**
+ * Closes a database connection, if it is open
+ * Returns success, true if already closed
+ */
+ function close() {
+ $this->mOpened = false;
+ if ($this->mConn) {
+ return oci_close($this->mConn);
+ } else {
+ return true;
+ }
+ }
+
+ function parseStatement($sql) {
+ $this->mErr = $this->mLastResult = false;
+ if (($stmt = oci_parse($this->mConn, $sql)) === false) {
+ $this->lastError();
+ return $this->mLastResult = false;
+ }
+ $this->mAffectedRows[$stmt] = 0;
+ return $this->mLastResult = $stmt;
+ }
+
+ function doQuery($sql) {
+ if (($stmt = $this->parseStatement($sql)) === false)
+ return false;
+ return $this->executeStatement($stmt);
+ }
+
+ function executeStatement($stmt) {
+ if (!oci_execute($stmt, OCI_DEFAULT)) {
+ $this->lastError();
+ oci_free_statement($stmt);
+ return false;
+ }
+ $this->mAffectedRows[$stmt] = oci_num_rows($stmt);
+ $this->mFetchCache[$stmt] = array();
+ $this->mFetchID[$stmt] = 0;
+ $this->mNcols[$stmt] = oci_num_fields($stmt);
+ if ($this->mNcols[$stmt] == 0)
+ return $this->mLastResult;
+ for ($i = 1; $i <= $this->mNcols[$stmt]; $i++) {
+ $this->mFieldNames[$stmt][$i] = oci_field_name($stmt, $i);
+ $this->mFieldTypes[$stmt][$i] = oci_field_type($stmt, $i);
+ }
+ while (($o = oci_fetch_array($stmt)) !== false) {
+ foreach ($o as $key => $value) {
+ if (is_object($value)) {
+ $o[$key] = $value->load();
+ }
+ }
+ $this->mFetchCache[$stmt][] = $o;
+ }
+ return $this->mLastResult;
+ }
+
+ function queryIgnore( $sql, $fname = '' ) {
+ return $this->query( $sql, $fname, true );
+ }
+
+ function freeResult( $res ) {
+ if (!oci_free_statement($res)) {
+ wfDebugDieBacktrace( "Unable to free Oracle result\n" );
+ }
+ unset($this->mFetchID[$res]);
+ unset($this->mFetchCache[$res]);
+ unset($this->mNcols[$res]);
+ unset($this->mFieldNames[$res]);
+ unset($this->mFieldTypes[$res]);
+ }
+
+ function fetchAssoc($res) {
+ if ($this->mFetchID[$res] >= count($this->mFetchCache[$res]))
+ return false;
+
+ for ($i = 1; $i <= $this->mNcols[$res]; $i++) {
+ $name = $this->mFieldNames[$res][$i];
+ $type = $this->mFieldTypes[$res][$i];
+ if (isset($this->mFetchCache[$res][$this->mFetchID[$res]][$name]))
+ $value = $this->mFetchCache[$res][$this->mFetchID[$res]][$name];
+ else $value = NULL;
+ $key = strtolower($name);
+ wfdebug("'$key' => '$value'\n");
+ $ret[$key] = $value;
+ }
+ $this->mFetchID[$res]++;
+ return $ret;
+ }
+
+ function fetchRow($res) {
+ $r = $this->fetchAssoc($res);
+ if (!$r)
+ return false;
+ $i = 0;
+ $ret = array();
+ foreach ($r as $key => $value) {
+ wfdebug("ret[$i]=[$value]\n");
+ $ret[$i++] = $value;
+ }
+ return $ret;
+ }
+
+ function fetchObject($res) {
+ $row = $this->fetchAssoc($res);
+ if (!$row)
+ return false;
+ $ret = new stdClass;
+ foreach ($row as $key => $value)
+ $ret->$key = $value;
+ return $ret;
+ }
+
+ function numRows($res) {
+ return count($this->mFetchCache[$res]);
+ }
+ function numFields( $res ) { return pg_num_fields( $res ); }
+ function fieldName( $res, $n ) { return pg_field_name( $res, $n ); }
+
+ /**
+ * This must be called after nextSequenceVal
+ */
+ function insertId() {
+ return $this->mInsertId;
+ }
+
+ function dataSeek($res, $row) {
+ $this->mFetchID[$res] = $row;
+ }
+
+ function lastError() {
+ if ($this->mErr === false) {
+ if ($this->mLastResult !== false) $what = $this->mLastResult;
+ else if ($this->mConn !== false) $what = $this->mConn;
+ else $what = false;
+ $err = ($what !== false) ? oci_error($what) : oci_error();
+ if ($err === false)
+ $this->mErr = 'no error';
+ else
+ $this->mErr = $err['message'];
+ }
+ return str_replace("\n", '<br />', $this->mErr);
+ }
+ function lastErrno() {
+ return 0;
+ }
+
+ function affectedRows() {
+ return $this->mAffectedRows[$this->mLastResult];
+ }
+
+ /**
+ * Returns information about an index
+ * If errors are explicitly ignored, returns NULL on failure
+ */
+ function indexInfo ($table, $index, $fname = 'Database::indexInfo' ) {
+ $table = $this->tableName($table, true);
+ if ($index == 'PRIMARY')
+ $index = "${table}_pk";
+ $sql = "SELECT uniqueness FROM all_indexes WHERE table_name='" .
+ $table . "' AND index_name='" .
+ $this->strencode(strtoupper($index)) . "'";
+ $res = $this->query($sql, $fname);
+ if (!$res)
+ return NULL;
+ if (($row = $this->fetchObject($res)) == NULL)
+ return false;
+ $this->freeResult($res);
+ $row->Non_unique = !$row->uniqueness;
+ return $row;
+ }
+
+ function indexUnique ($table, $index, $fname = 'indexUnique') {
+ if (!($i = $this->indexInfo($table, $index, $fname)))
+ return $i;
+ return $i->uniqueness == 'UNIQUE';
+ }
+
+ function fieldInfo( $table, $field ) {
+ $o = new stdClass;
+ $o->multiple_key = true; /* XXX */
+ return $o;
+ }
+
+ function getColumnInformation($table, $field) {
+ $table = $this->tableName($table, true);
+ $field = strtoupper($field);
+
+ $res = $this->doQuery("SELECT * FROM all_tab_columns " .
+ "WHERE table_name='".$table."' " .
+ "AND column_name='".$field."'");
+ if (!$res)
+ return false;
+ $o = $this->fetchObject($res);
+ $this->freeResult($res);
+ return $o;
+ }
+
+ function fieldExists( $table, $field, $fname = 'Database::fieldExists' ) {
+ $column = $this->getColumnInformation($table, $field);
+ if (!$column)
+ return false;
+ return true;
+ }
+
+ function startTimer( $timeout )
+ {
+ global $IP;
+ wfDebugDieBacktrace( 'Database::startTimer() error : mysql_thread_id() not implemented for postgre' );
+ /*$tid = mysql_thread_id( $this->mConn );
+ exec( "php $IP/killthread.php $timeout $tid &>/dev/null &" );*/
+ }
+
+ function tableName($name, $forddl = false) {
+ # First run any transformations from the parent object
+ $name = parent::tableName( $name );
+
+ # Replace backticks into empty
+ # Note: "foo" and foo are not the same in Oracle!
+ $name = str_replace('`', '', $name);
+
+ # Now quote Oracle reserved keywords
+ switch( $name ) {
+ case 'user':
+ case 'group':
+ case 'validate':
+ if ($forddl)
+ return $name;
+ else
+ return '"' . $name . '"';
+
+ default:
+ return strtoupper($name);
+ }
+ }
+
+ function strencode( $s ) {
+ return str_replace("'", "''", $s);
+ }
+
+ /**
+ * Return the next in a sequence, save the value for retrieval via insertId()
+ */
+ function nextSequenceValue( $seqName ) {
+ $r = $this->doQuery("SELECT $seqName.nextval AS val FROM dual");
+ $o = $this->fetchObject($r);
+ $this->freeResult($r);
+ return $this->mInsertId = (int)$o->val;
+ }
+
+ /**
+ * USE INDEX clause
+ * PostgreSQL doesn't have them and returns ""
+ */
+ function useIndexClause( $index ) {
+ return '';
+ }
+
+ # REPLACE query wrapper
+ # PostgreSQL simulates this with a DELETE followed by INSERT
+ # $row is the row to insert, an associative array
+ # $uniqueIndexes is an array of indexes. Each element may be either a
+ # field name or an array of field names
+ #
+ # 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' ) {
+ $table = $this->tableName( $table );
+
+ if (count($rows)==0) {
+ return;
+ }
+
+ # Single row case
+ if ( !is_array( reset( $rows ) ) ) {
+ $rows = array( $rows );
+ }
+
+ foreach( $rows as $row ) {
+ # Delete rows which collide
+ if ( $uniqueIndexes ) {
+ $sql = "DELETE FROM $table WHERE ";
+ $first = true;
+ foreach ( $uniqueIndexes as $index ) {
+ if ( $first ) {
+ $first = false;
+ $sql .= "(";
+ } else {
+ $sql .= ') OR (';
+ }
+ if ( is_array( $index ) ) {
+ $first2 = true;
+ foreach ( $index as $col ) {
+ if ( $first2 ) {
+ $first2 = false;
+ } else {
+ $sql .= ' AND ';
+ }
+ $sql .= $col.'=' . $this->addQuotes( $row[$col] );
+ }
+ } else {
+ $sql .= $index.'=' . $this->addQuotes( $row[$index] );
+ }
+ }
+ $sql .= ')';
+ $this->query( $sql, $fname );
+ }
+
+ # 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 );
+ }
+ }
+
+ # DELETE where the condition is a join
+ function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = "Database::deleteJoin" ) {
+ if ( !$conds ) {
+ wfDebugDieBacktrace( 'Database::deleteJoin() called with empty $conds' );
+ }
+
+ $delTable = $this->tableName( $delTable );
+ $joinTable = $this->tableName( $joinTable );
+ $sql = "DELETE FROM $delTable WHERE $delVar IN (SELECT $joinVar FROM $joinTable ";
+ if ( $conds != '*' ) {
+ $sql .= 'WHERE ' . $this->makeList( $conds, LIST_AND );
+ }
+ $sql .= ')';
+
+ $this->query( $sql, $fname );
+ }
+
+ # Returns the size of a text field, or -1 for "unlimited"
+ function textFieldSize( $table, $field ) {
+ $table = $this->tableName( $table );
+ $sql = "SELECT t.typname as ftype,a.atttypmod as size
+ FROM pg_class c, pg_attribute a, pg_type t
+ WHERE relname='$table' AND a.attrelid=c.oid AND
+ a.atttypid=t.oid and a.attname='$field'";
+ $res =$this->query($sql);
+ $row=$this->fetchObject($res);
+ if ($row->ftype=="varchar") {
+ $size=$row->size-4;
+ } else {
+ $size=$row->size;
+ }
+ $this->freeResult( $res );
+ return $size;
+ }
+
+ function lowPriorityOption() {
+ return '';
+ }
+
+ function limitResult($sql, $limit, $offset) {
+ $ret = "SELECT * FROM ($sql) WHERE ROWNUM < " . ((int)$limit + (int)($offset+1));
+ if (is_numeric($offset))
+ $ret .= " AND ROWNUM >= " . (int)$offset;
+ return $ret;
+ }
+ function limitResultForUpdate($sql, $limit) {
+ return $sql;
+ }
+ /**
+ * Returns an SQL expression for a simple conditional.
+ * Uses CASE on PostgreSQL.
+ *
+ * @param string $cond SQL expression which will result in a boolean value
+ * @param string $trueVal SQL expression to return if true
+ * @param string $falseVal SQL expression to return if false
+ * @return string SQL fragment
+ */
+ function conditional( $cond, $trueVal, $falseVal ) {
+ return " (CASE WHEN $cond THEN $trueVal ELSE $falseVal END) ";
+ }
+
+ # FIXME: actually detecting deadlocks might be nice
+ function wasDeadlock() {
+ return false;
+ }
+
+ # Return DB-style timestamp used for MySQL schema
+ function timestamp($ts = 0) {
+ return $this->strencode(wfTimestamp(TS_ORACLE, $ts));
+# return "TO_TIMESTAMP('" . $this->strencode(wfTimestamp(TS_DB, $ts)) . "', 'RRRR-MM-DD HH24:MI:SS')";
+ }
+
+ function notNullTimestamp() {
+ return "IS NOT NULL";
+ }
+ function isNullTimestamp() {
+ return "IS NULL";
+ }
+ /**
+ * Return aggregated value function call
+ */
+ function aggregateValue ($valuedata,$valuename='value') {
+ return $valuedata;
+ }
+
+
+ function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
+ $message = "A database error has occurred\n" .
+ "Query: $sql\n" .
+ "Function: $fname\n" .
+ "Error: $errno $error\n";
+ wfDebugDieBacktrace($message);
+ }
+
+ /**
+ * @return string wikitext of a link to the server software's web site
+ */
+ function getSoftwareLink() {
+ return "[http://www.oracle.com/ Oracle]";
+ }
+
+ /**
+ * @return string Version information from the database
+ */
+ function getServerVersion() {
+ return oci_server_version($this->mConn);
+ }
+
+ function setSchema($schema=false) {
+ $schemas=$this->mSchemas;
+ if ($schema) { array_unshift($schemas,$schema); }
+ $searchpath=$this->makeList($schemas,LIST_NAMES);
+ $this->query("SET search_path = $searchpath");
+ }
+
+ function begin() {
+ }
+
+ function immediateCommit( $fname = 'Database::immediateCommit' ) {
+ oci_commit($this->mConn);
+ $this->mTrxLevel = 0;
+ }
+ function rollback( $fname = 'Database::rollback' ) {
+ oci_rollback($this->mConn);
+ $this->mTrxLevel = 0;
+ }
+ function getLag() {
+ return false;
+ }
+ function getStatus() {
+ $result = array('Threads_running' => 0, 'Threads_connected' => 0);
+ return $result;
+ }
+
+ /**
+ * Returns an optional USE INDEX clause to go after the table, and a
+ * string to go at the end of the query
+ *
+ * @access private
+ *
+ * @param array $options an associative array of options to be turned into
+ * an SQL query, valid keys are listed in the function.
+ * @return array
+ */
+ function makeSelectOptions($options) {
+ $tailOpts = '';
+
+ if (isset( $options['ORDER BY'])) {
+ $tailOpts .= " ORDER BY {$options['ORDER BY']}";
+ }
+
+ return array('', $tailOpts);
+ }
+
+ function maxListLen() {
+ return 1000;
+ }
+
+ /**
+ * Query whether a given table exists
+ */
+ function tableExists( $table ) {
+ $table = $this->tableName($table, true);
+ $res = $this->query( "SELECT COUNT(*) as NUM FROM user_tables WHERE table_name='"
+ . $table . "'" );
+ if (!$res)
+ return false;
+ $row = $this->fetchObject($res);
+ $this->freeResult($res);
+ return $row->num >= 1;
+ }
+
+ /**
+ * UPDATE wrapper, takes a condition array and a SET array
+ */
+ function update( $table, $values, $conds, $fname = 'Database::update' ) {
+ $table = $this->tableName( $table );
+
+ $sql = "UPDATE $table SET ";
+ $first = true;
+ foreach ($values as $field => $v) {
+ if ($first)
+ $first = false;
+ else
+ $sql .= ", ";
+ $sql .= "$field = :n$field ";
+ }
+ if ( $conds != '*' ) {
+ $sql .= " WHERE " . $this->makeList( $conds, LIST_AND );
+ }
+ $stmt = $this->parseStatement($sql);
+ if ($stmt === false) {
+ $this->reportQueryError( $this->lastError(), $this->lastErrno(), $stmt );
+ return false;
+ }
+ if ($this->debug())
+ wfDebug("SQL: $sql\n");
+ $s = '';
+ foreach ($values as $field => $v) {
+ oci_bind_by_name($stmt, ":n$field", $values[$field]);
+ if ($this->debug())
+ $s .= " [$field] = [$v]\n";
+ }
+ if ($this->debug())
+ wfdebug(" PH: $s\n");
+ $ret = $this->executeStatement($stmt);
+ return $ret;
+ }
+
+ /**
+ * INSERT wrapper, inserts an array into a table
+ *
+ * $a may be a single associative array, or an array of these with numeric keys, for
+ * multi-row insert.
+ *
+ * Usually aborts on failure
+ * If errors are explicitly ignored, returns success
+ */
+ function insert( $table, $a, $fname = 'Database::insert', $options = array() ) {
+ # No rows to insert, easy just return now
+ if ( !count( $a ) ) {
+ return true;
+ }
+
+ $table = $this->tableName( $table );
+ if (!is_array($options))
+ $options = array($options);
+
+ $oldIgnore = false;
+ if (in_array('IGNORE', $options))
+ $oldIgnore = $this->ignoreErrors( true );
+
+ if ( isset( $a[0] ) && is_array( $a[0] ) ) {
+ $multi = true;
+ $keys = array_keys( $a[0] );
+ } else {
+ $multi = false;
+ $keys = array_keys( $a );
+ }
+
+ $sql = "INSERT INTO $table (" . implode( ',', $keys ) . ') VALUES (';
+ $return = '';
+ $first = true;
+ foreach ($a as $key => $value) {
+ if ($first)
+ $first = false;
+ else
+ $sql .= ", ";
+ if (is_object($value) && $value->isLOB()) {
+ $sql .= "EMPTY_BLOB()";
+ $return = "RETURNING $key INTO :bobj";
+ } else
+ $sql .= ":$key";
+ }
+ $sql .= ") $return";
+
+ if ($this->debug()) {
+ wfDebug("SQL: $sql\n");
+ }
+
+ if (($stmt = $this->parseStatement($sql)) === false) {
+ $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname);
+ $this->ignoreErrors($oldIgnore);
+ return false;
+ }
+
+ /*
+ * If we're inserting multiple rows, parse the statement once and
+ * execute it for each set of values. Otherwise, convert it into an
+ * array and pretend.
+ */
+ if (!$multi)
+ $a = array($a);
+
+ foreach ($a as $key => $row) {
+ $blob = false;
+ $bdata = false;
+ $s = '';
+ foreach ($row as $k => $value) {
+ if (is_object($value) && $value->isLOB()) {
+ $blob = oci_new_descriptor($this->mConn, OCI_D_LOB);
+ $bdata = $value->data();
+ oci_bind_by_name($stmt, ":bobj", &$blob, -1, OCI_B_BLOB);
+ } else
+ oci_bind_by_name($stmt, ":$k", $a[$key][$k], -1);
+ if ($this->debug())
+ $s .= " [$k] = {$row[$k]}";
+ }
+ if ($this->debug())
+ wfDebug(" PH: $s\n");
+ if (($s = $this->executeStatement($stmt)) === false) {
+ $this->reportQueryError($this->lastError(), $this->lastErrno(), $sql, $fname);
+ $this->ignoreErrors($oldIgnore);
+ return false;
+ }
+
+ if ($blob) {
+ $blob->save($bdata);
+ }
+ }
+ $this->ignoreErrors($oldIgnore);
+ return $this->mLastResult = $s;
+ }
+
+ function ping() {
+ return true;
+ }
+
+ function encodeBlob($b) {
+ return new OracleBlob($b);
+ }
+}
+
+?>
var $mArticle;
var $mTitle;
var $mMetaData = '';
-
+
# Form values
var $save = false, $preview = false, $diff = false;
var $minoredit = false, $watchthis = false;
var $textbox1 = '', $textbox2 = '', $summary = '';
var $edittime = '', $section = '';
var $oldid = 0;
-
+
/**
* @todo document
* @param $article
{
$sat[] = strtolower ( $x ) ;
}
-
+
}
# Templates, but only some
$wgOut->setArticleFlag(false);
$this->importFormData( $wgRequest );
-
+
if( $this->live ) {
$this->livePreview();
return;
}
}
}
-
+
/**
* Return true if this page should be previewed when the edit form
* is initially opened.
$this->textbox2 = $this->safeUnicodeInput( $request, 'wpTextbox2' );
$this->mMetaData = rtrim( $request->getText( 'metadata' ) );
$this->summary = $request->getText( 'wpSummary' );
-
+
$this->edittime = $request->getVal( 'wpEdittime' );
if( is_null( $this->edittime ) ) {
# If the form is incomplete, force to preview.
if( !preg_match( '/^\d{14}$/', $this->edittime )) {
$this->edittime = null;
}
-
+
$this->minoredit = $request->getCheck( 'wpMinoredit' );
$this->watchthis = $request->getCheck( 'wpWatchthis' );
} else {
# Section edit can come from either the form or a link
$this->section = $request->getVal( 'wpSection', $request->getVal( 'section' ) );
-
+
$this->live = $request->getCheck( 'live' );
}
return $wgUser->matchEditToken( $request->getVal( 'wpEditToken' ) );
}
}
-
+
function submit() {
$this->edit();
}
if(isset($introtitle) && $introtitle->userCanRead()) {
$rev=Revision::newFromTitle($introtitle);
if($rev) {
- $wgOut->addWikiText($rev->getText());
+ $wgOut->addWikiText($rev->getText());
$addstandardintro=false;
}
}
$this->mArticle->clear(); # Force reload of dates, etc.
$this->mArticle->forUpdate( true ); # Lock the article
+wfdebug("CONFLICT: edittime=".$this->edittime." article timestamp=".$this->mArticle->getTimestamp()."\n");
if( ( $this->section != 'new' ) &&
($this->mArticle->getTimestamp() != $this->edittime ) ) {
$isConflict = true;
# XXX: might be better to integrate this into Article::getTextOfLastEditWithSectionReplacedOrAdded
# for duplicate heading checking and maybe parsing
$hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
- # we can't deal with anchors, includes, html etc in the header for now,
+ # we can't deal with anchors, includes, html etc in the header for now,
# headline would need to be parsed to improve this
#if($hasmatch and strlen($matches[2]) > 0 and !preg_match( "/[\\['{<>]/", $matches[2])) {
if($hasmatch and strlen($matches[2]) > 0) {
$this->section = '';
if (wfRunHooks('ArticleSave', array(&$this->mArticle, &$wgUser, &$text,
- &$this->summary, &$this->minoredit,
- &$this->watchthis, &$sectionanchor)))
+ &$this->summary, &$this->minoredit,
+ &$this->watchthis, &$sectionanchor)))
{
# update the article here
if($this->mArticle->updateArticle( $text, $this->summary, $this->minoredit,
- $this->watchthis, '', $sectionanchor ))
+ $this->watchthis, '', $sectionanchor ))
{
- wfRunHooks('ArticleSaveComplete', array(&$this->mArticle, &$wgUser, $text,
- $this->summary, $this->minoredit,
- $this->watchthis, $sectionanchor));
+ wfRunHooks('ArticleSaveComplete',
+ array(&$this->mArticle, &$wgUser, $text,
+ $this->summary, $this->minoredit,
+ $this->watchthis, $sectionanchor));
return;
} else {
$isConflict = true;
$watchhtml = '';
if ( $wgUser->isLoggedIn() ) {
- $watchhtml = "<input tabindex='4' type='checkbox' name='wpWatchthis'".($this->watchthis?" checked='checked'":"").
- " accesskey='".wfMsg('accesskey-watch')."' id='wpWatchthis' />".
- "<label for='wpWatchthis' title='".wfMsg('tooltip-watch')."'>{$watchthis}</label>";
+ $watchhtml = "<input tabindex='4' type='checkbox' name='wpWatchthis'".
+ ($this->watchthis?" checked='checked'":"").
+ " accesskey=\"".htmlspecialchars(wfMsg('accesskey-watch'))."\" id='wpWatchthis' />".
+ "<label for='wpWatchthis' title=\"" .
+ htmlspecialchars(wfMsg('tooltip-watch'))."\">{$watchthis}</label>";
}
$checkboxhtml = $minoredithtml . $watchhtml . '<br />';
$wgOut->addHTML( $previewOutput );
if($this->mTitle->getNamespace() == NS_CATEGORY) {
$this->mArticle->closeShowCategory();
- }
+ }
$wgOut->addHTML( "<br style=\"clear:both;\" />\n" );
}
}
}
$templates .= '</ul>';
}
-
+
global $wgLivePreview, $wgStylePath;
/**
* Live Preview lets us fetch rendered preview page content and
} else {
$liveOnclick = '';
}
-
+
global $wgUseMetadataEdit ;
if ( $wgUseMetadataEdit )
{
$wgOut->addHTML( "
<input type='hidden' value=\"$token\" name=\"wpEditToken\" />\n" );
}
-
-
+
+
if ( $isConflict ) {
require_once( "DifferenceEngine.php" );
$wgOut->addWikiText( '==' . wfMsg( "yourdiff" ) . '==' );
}
if ( $this->mMetaData != "" ) $toparse .= "\n" . $this->mMetaData ;
-
+
$parserOutput = $wgParser->parse( $this->mArticle->preSaveTransform( $toparse ) ."\n\n",
- $wgTitle, $parserOptions );
-
+ $wgTitle, $parserOptions );
+
$previewHTML = $parserOutput->mText;
-
+
$wgOut->addCategoryLinks($parserOutput->getCategoryLinks());
$wgOut->addLanguageLinks($parserOutput->getLanguageLinks());
return $previewhead . $previewHTML;
}
}
-
+
/**
* @todo document
*/
$id = $wgUser->blockedBy();
$reason = $wgUser->blockedFor();
$ip = $wgIP;
-
+
if ( is_numeric( $id ) ) {
$name = User::whoIs( $id );
} else {
function proxyCheck() {
global $wgBlockOpenProxies, $wgProxyPorts, $wgProxyScriptPath;
global $wgIP, $wgUseMemCached, $wgMemc, $wgDBname, $wgProxyMemcExpiry;
-
+
if ( !$wgBlockOpenProxies ) {
return;
}
-
+
# Get MemCached key
$skip = false;
if ( $wgUseMemCached ) {
wfProfileIn( $fname );
$db =& wfGetDB( DB_MASTER );
-
+
// This is the revision the editor started from
$baseRevision = Revision::loadFromTimestamp(
$db, $this->mArticle->mTitle, $this->edittime );
return false;
}
$currentText = $currentRevision->getText();
-
+
if( wfMerge( $baseText, $editText, $currentText, $result ) ){
$editText = $result;
wfProfileOut( $fname );
*/
function sectionAnchor( $text ) {
$headline = Sanitizer::decodeCharReferences( $text );
- # strip out HTML
+ # strip out HTML
$headline = preg_replace( '/<.*?' . '>/', '', $headline );
$headline = trim( $headline );
$sectionanchor = '#' . urlencode( str_replace( ' ', '_', $headline ) );
$toolbar.="/*]]>*/\n</script>";
return $toolbar;
}
-
+
/**
* Output preview text only. This can be sucked into the edit page
* via JavaScript, and saves the server time rendering the skin as
if ( $oldtext != wfMsg( 'noarticletext' ) || $newtext != '' ) {
$difftext = DifferenceEngine::getDiff( $oldtext, $newtext, $oldtitle, $newtitle );
}
-
+
return '<div id="wikiDiff">' . $difftext . '</div>';
}
/**
* Some globals and requires needed
*/
-
+
/**
* Total number of articles
* @global integer $wgNumberOfArticles
# UTF-8 substr function based on a PHP manual comment
if ( !function_exists( 'mb_substr' ) ) {
- function mb_substr( $str, $start ) {
+ function mb_substr( $str, $start ) {
preg_match_all( '/./us', $str, $ar );
if( func_num_args() >= 3 ) {
- $end = func_get_arg( 2 );
- return join( '', array_slice( $ar[0], $start, $end ) );
- } else {
- return join( '', array_slice( $ar[0], $start ) );
+ $end = func_get_arg( 2 );
+ return join( '', array_slice( $ar[0], $start, $end ) );
+ } else {
+ return join( '', array_slice( $ar[0], $start ) );
}
}
}
if ( '' == $wgReadOnlyFile ) {
return false;
}
-
+
// Set $wgReadOnly and unset $wgReadOnlyFile, for faster access next time
if ( is_file( $wgReadOnlyFile ) ) {
$wgReadOnly = true;
/**
* Get a message from anywhere, for the current user language
*
- * @param string
+ * @param string
*/
function wfMsg( $key ) {
$args = func_get_args();
function wfMsgReal( $key, $args, $useDB, $forContent=false ) {
$fname = 'wfMsgReal';
wfProfileIn( $fname );
-
+
$message = wfMsgGetKey( $key, $useDB, $forContent );
$message = wfMsgReplaceArgs( $message, $args );
wfProfileOut( $fname );
global $wgParser, $wgMsgParserOptions;
global $wgContLang, $wgLanguageCode;
global $wgMessageCache, $wgLang;
-
+
if( is_object( $wgMessageCache ) ) {
$message = $wgMessageCache->get( $key, $useDB, $forContent );
} else {
}
wfSuppressWarnings();
-
+
if( is_object( $lang ) ) {
$message = $lang->getMessage( $key );
} else {
*/
function wfMsgReplaceArgs( $message, $args ) {
static $replacementKeys = array( '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9' );
-
+
# Fix windows line-endings
# Some messages are split with explode("\n", $msg)
$message = str_replace( "\r", '', $message );
if ( !function_exists( 'debug_backtrace' ) ) {
return false;
}
-
+
if ( $wgCommandLineMode ) {
$msg = '';
} else {
$fmtLimit = $wgLang->formatNum( $limit );
$prev = wfMsg( 'prevn', $fmtLimit );
$next = wfMsg( 'nextn', $fmtLimit );
-
+
if( is_object( $link ) ) {
$title =& $link;
} else {
return false;
}
}
-
+
$sk = $wgUser->getSkin();
if ( 0 != $offset ) {
$po = $offset - $limit;
* @param string $text Text to be escaped
*/
function wfEscapeWikiText( $text ) {
- $text = str_replace(
+ $text = str_replace(
array( '[', '|', '\'', 'ISBN ' , '://' , "\n=", '{{' ),
array( '[', '|', ''', 'ISBN ', '://' , "\n=", '{{' ),
htmlspecialchars($text) );
'\'' => '\\\'',
"\n" => "\\n",
"\r" => "\\r",
-
+
# To avoid closing the element or CDATA section
"<" => "\\x3c",
">" => "\\x3e",
/**
* Windows-compatible version of escapeshellarg()
- * Windows doesn't recognise single-quotes in the shell, but the escapeshellarg()
+ * Windows doesn't recognise single-quotes in the shell, but the escapeshellarg()
* function puts single quotes in regardless of OS
*/
function wfEscapeShellArg( ) {
} else {
$first = false;
}
-
+
if ( wfIsWindows() ) {
$retVal .= '"' . str_replace( '"','\"', $arg ) . '"';
} else {
header( 'Content-type: text/html' );
print "<html><head><title>" .
- htmlspecialchars( $label ) .
- "</title></head><body><h1>" .
+ htmlspecialchars( $label ) .
+ "</title></head><body><h1>" .
htmlspecialchars( $label ) .
"</h1><p>" .
htmlspecialchars( $desc ) .
* Array lookup
* Returns an array where the values in the first array are replaced by the
* values in the second array with the corresponding keys
- *
+ *
* @return array
*/
function wfArrayLookup( $a, $b ) {
# Autodetect, convert and provide timestamps of various types
-/**
+/**
* Unix time - the number of seconds since 1970-01-01 00:00:00 UTC
*/
define('TS_UNIX', 0);
*/
define('TS_EXIF', 4);
+/**
+ * Oracle format time.
+ */
+define('TS_ORACLE', 5);
/**
* @param mixed $outputtype A timestamp in one of the supported formats, the
* @return string Time in the format specified in $outputtype
*/
function wfTimestamp($outputtype=TS_UNIX,$ts=0) {
- if ($ts==0) {
- $uts=time();
+wfdebug("ts: $ts\n");
+ if ($ts==0) {
+ $uts=time();
} elseif (preg_match("/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/",$ts,$da)) {
# TS_DB
$uts=gmmktime((int)$da[4],(int)$da[5],(int)$da[6],
} elseif (preg_match("/^(\d{1,13})$/",$ts,$datearray)) {
# TS_UNIX
$uts=$ts;
+ } elseif (preg_match('/^(\d{1,2})-(...)-(\d\d(\d\d)?) (\d\d)\.(\d\d)\.(\d\d)/', $ts, $da)) {
+ # TS_ORACLE
+ $uts = strtotime(preg_replace('/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
+ str_replace("+00:00", "UTC", $ts)));
} else {
# Bogus value; fall back to the epoch...
wfDebug("wfTimestamp() fed bogus time value: $outputtype; $ts\n");
$uts = 0;
}
-
+
switch($outputtype) {
case TS_UNIX:
return $uts;
return gmdate( 'Y:m:d H:i:s', $uts );
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';
default:
wfDebugDieBacktrace( 'wfTimestamp() called with illegal output type.');
}
*
* @return bool True if it's windows, False otherwise.
*/
-function wfIsWindows() {
- if (substr(php_uname(), 0, 7) == 'Windows') {
- return true;
- } else {
- return false;
- }
-}
+function wfIsWindows() {
+ if (substr(php_uname(), 0, 7) == 'Windows') {
+ return true;
+ } else {
+ return false;
+ }
+}
/**
* Swap two variables
/** Global singleton instance of MimeMagic. This is initialized on demand,
* please always use the wfGetMimeMagic() function to get the instance.
-*
+*
* @private
*/
$wgMimeMagic= NULL;
*/
function &wfGetMimeMagic() {
global $wgMimeMagic;
-
+
if (!is_null($wgMimeMagic)) {
return $wgMimeMagic;
}
#include on demand
require_once("MimeMagic.php");
}
-
+
$wgMimeMagic= new MimeMagic();
-
+
return $wgMimeMagic;
}
if ( $line ) {
$list =& new ImageHistoryList( $sk );
$s = $list->beginImageHistoryList() .
- $list->imageHistoryLine( true, $line->img_timestamp,
+ $list->imageHistoryLine( true, wfTimestamp(TS_MW, $line->img_timestamp),
$this->mTitle->getDBkey(), $line->img_user,
$line->img_user_text, $line->img_size, $line->img_description );
$imagelinks = $dbr->tableName( 'imagelinks' );
$sql = "SELECT page_namespace,page_title FROM $imagelinks,$page WHERE il_to=" .
- $dbr->addQuotes( $this->mTitle->getDBkey() ) . " AND il_from=page_id"
- . " LIMIT 500"; # quickie emergency brake
+ $dbr->addQuotes( $this->mTitle->getDBkey() ) . " AND il_from=page_id";
+ $sql = $dbr->limitResult($sql, 500, 0);
$res = $dbr->query( $sql, "ImagePage::imageLinks" );
if ( 0 == $dbr->numRows( $res ) ) {
* @package MediaWiki
* @subpackage Cache
*/
-class LinkCache {
+class LinkCache {
// Increment $mClassVer whenever old serialized versions of this class
// becomes incompatible with the new version.
/* private */ var $mClassVer = 3;
global $wgDBname;
return $wgDBname.':lc:title:'.$title;
}
-
+
function LinkCache() {
$this->mActive = true;
$this->mPreFilled = false;
/**
* General accessor to get/set whether SELECT FOR UPDATE should be used
*/
- function forUpdate( $update = NULL ) {
+ function forUpdate( $update = NULL ) {
return wfSetVar( $this->mForUpdate, $update );
}
-
+
function getGoodLinkID( $title ) {
if ( array_key_exists( $title, $this->mGoodLinks ) ) {
return $this->mGoodLinks[$title];
}
function isBadLink( $title ) {
- return array_key_exists( $title, $this->mBadLinks );
+ return array_key_exists( $title, $this->mBadLinks );
}
function addGoodLinkObj( $id, $title ) {
function addImageLinkObj( $nt ) {
if ( $this->mActive ) { $this->mImageLinks[$nt->getDBkey()] = 1; }
}
-
+
function addCategoryLink( $title, $sortkey ) {
if ( $this->mActive ) { $this->mCategoryLinks[$title] = $sortkey; }
}
-
+
function addCategoryLinkObj( &$nt, $sortkey ) {
$this->addCategoryLink( $nt->getDBkey(), $sortkey );
}
unset( $this->mBadLinks[$title] );
$this->clearLink( $title );
}
-
+
function clearLink( $title ) {
global $wgMemc, $wgLinkCacheMemcached;
if( $wgLinkCacheMemcached )
return 0;
}
}
-
+
function addLinkObj( &$nt ) {
global $wgMemc, $wgLinkCacheMemcached, $wgAntiLockFlags;
$title = $nt->getPrefixedDBkey();
- if ( $this->isBadLink( $title ) ) { return 0; }
+ if ( $this->isBadLink( $title ) ) { return 0; }
$id = $this->getGoodLinkID( $title );
if ( 0 != $id ) { return $id; }
$ns = $nt->getNamespace();
$t = $nt->getDBkey();
- if ( '' == $title ) {
+ if ( '' == $title ) {
wfProfileOut( $fname );
- return 0;
+ return 0;
}
-
+
$id = NULL;
if( $wgLinkCacheMemcached )
$id = $wgMemc->get( $key = $this->getKey( $title ) );
$options = array();
}
- $id = $db->selectField( 'page', 'page_id', array( 'page_namespace' => $ns, 'page_title' => $t ), $fname, $options );
+ $id = $db->selectField( 'page', 'page_id',
+ array( 'page_namespace' => $ns, 'page_title' => $t ),
+ $fname, $options );
+wfdebug("link cache: id=$id\n");
if ( !$id ) {
$id = 0;
}
if( $wgLinkCacheMemcached )
$wgMemc->add( $key, $id, 3600*24 );
}
-
+
if( 0 == $id ) {
$this->addBadLinkObj( $nt );
} else {
$this->suspend();
$id = $fromtitle->getArticleID();
$this->resume();
-
+
if( $id == 0 ) {
wfDebug( "$fname - got id 0 for title '" . $fromtitle->getPrefixedDBkey() . "'\n" );
wfProfileOut( $fname );
return;
}
-
+
if ( $this->mForUpdate ) {
$db =& wfGetDB( DB_MASTER );
if ( !( $wgAntiLockFlags & ALF_NO_LINK_LOCK ) ) {
function getImageDeletions() {
return array_diff_assoc( $this->mOldImageLinks, $this->mImageLinks );
}
-
+
function getPageAdditions() {
$set = array_diff( array_keys( $this->mPageLinks ), array_keys( $this->mOldPageLinks ) );
$out = array();
}
return $out;
}
-
+
function getPageDeletions() {
$set = array_diff( array_keys( $this->mOldPageLinks ), array_keys( $this->mPageLinks ) );
$out = array();
$add = $this->getPageAdditions();
break;
default: # LINKCACHE_IMAGE
- return false;
+ return false;
}
-
+
return true;
}
/**
- * Clears cache
+ * Clears cache
*/
function clear() {
$this->mPageLinks = array();
* @subpackage Cache
*/
class LinkBatch {
- /**
+ /**
* 2-d array, first index namespace, second index dbkey, value arbitrary
*/
var $data = array();
$this->addObj( $item );
}
}
-
+
function addObj( $title ) {
$this->add( $title->getNamespace(), $title->getDBkey() );
}
$page = $dbr->tableName( 'page' );
$sql = "SELECT page_id, page_namespace, page_title FROM $page WHERE "
. $this->constructSet( 'page', $dbr );
-
+
// Do query
$res = $dbr->query( $sql, $fname );
wfProfileOut( $fname );
}
-
+
/**
* Construct a WHERE clause which will match all the given titles.
* Give the appropriate table's field name prefix ('page', 'pl', etc).
$this->mGroupLoads[$group][$i] = $ratio;
}
}
- }
+ }
}
-
+
/**
* Given an array of non-normalised probabilities, this function will select
* an element and return the appropriate key
}
$max = mt_getrandmax();
$rand = mt_rand(0, $max) / $max * $sum;
-
+
$sum = 0;
foreach ( $weights as $i => $w ) {
$sum += $w;
if ( $sum == 0 ) {
# No appropriate DB servers except maybe the master and some slaves with zero load
# Do NOT use the master
- # Instead, this function will return false, triggering read-only mode,
+ # Instead, this function will return false, triggering read-only mode,
# and a lagged slave will be used instead.
unset ( $loads[0] );
}
/**
* Get the index of the reader connection, which may be a slave
- * This takes into account load ratios and lag times. It should
+ * This takes into account load ratios and lag times. It should
* always return a consistent index during a given invocation
*
* Side effect: opens connections to databases
if ( $i !== false ) {
wfDebug( "Using reader #$i: {$this->mServers[$i]['host']}...\n" );
$this->openConnection( $i );
-
+
if ( !$this->isOpen( $i ) ) {
wfDebug( "Failed\n" );
unset( $loads[$i] );
$sleepTime = 0;
} else {
$status = $this->mConnections[$i]->getStatus();
- if ( isset( $this->mServers[$i]['max threads'] ) &&
- $status['Threads_running'] > $this->mServers[$i]['max threads'] )
+ if ( isset( $this->mServers[$i]['max threads'] ) &&
+ $status['Threads_running'] > $this->mServers[$i]['max threads'] )
{
# Slave is lagged, wait for a while
$sleepTime = 5000 * $status['Threads_connected'];
wfProfileOut( $fname );
return $i;
}
-
+
/**
* Get a random server to use in a query group
*/
wfDebug( "Query group $group => $i\n" );
return $i;
}
-
+
/**
* Set the master wait position
* If a DB_SLAVE connection has been opened already, waits
$this->mServers[$i]['slave pos'] = $this->mConnections[$i]->getSlavePos();
$this->mLaggedSlaveMode = true;
}
- }
+ }
}
wfProfileOut( $fname );
}
*/
function doWait( $index ) {
global $wgMemc;
-
+
$retVal = false;
# Debugging hacks
}
}
return $retVal;
- }
+ }
/**
* Get a connection by index
{
$fname = 'LoadBalancer::getConnection';
wfProfileIn( $fname );
-
+
# Query groups
$groupIndex = false;
foreach ( $groups as $group ) {
break;
}
}
-
+
# Operation-based index
- if ( $i == DB_SLAVE ) {
+ if ( $i == DB_SLAVE ) {
$i = $this->getReaderIndex();
} elseif ( $i == DB_MASTER ) {
$i = $this->getWriterIndex();
}
# Now we have an explicit index into the servers array
$this->openConnection( $i, $fail );
-
+
wfProfileOut( $fname );
return $this->mConnections[$i];
}
if ( !$this->isOpen( $i ) ) {
$this->mConnections[$i] = $this->reallyOpenConnection( $this->mServers[$i] );
}
+
if ( !$this->isOpen( $i ) ) {
wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
if ( $fail ) {
if( !is_integer( $index ) ) {
return false;
}
- if ( array_key_exists( $index, $this->mConnections ) && is_object( $this->mConnections[$index] ) &&
- $this->mConnections[$index]->isOpen() )
+ if ( array_key_exists( $index, $this->mConnections ) && is_object( $this->mConnections[$index] ) &&
+ $this->mConnections[$index]->isOpen() )
{
return true;
} else {
return false;
}
}
-
+
/**
* Really opens a connection
* @private
if( !is_array( $server ) ) {
wfDebugDieBacktrace( 'You must update your load-balancing configuration. See DefaultSettings.php entry for $wgDBservers.' );
}
-
+
extract( $server );
# Get class for this database type
$class = 'Database' . ucfirst( $type );
# Create object
return new $class( $host, $user, $password, $dbname, 1, $flags );
}
-
+
function reportConnectionError( &$conn )
{
$fname = 'LoadBalancer::reportConnectionError';
wfProfileIn( $fname );
# Prevent infinite recursion
-
+
static $reporting = false;
if ( !$reporting ) {
$reporting = true;
}
wfProfileOut( $fname );
}
-
+
function getWriterIndex()
{
return 0;
function saveMasterPos() {
global $wgSessionStarted;
if ( $wgSessionStarted && count( $this->mServers ) > 1 ) {
- # If this entire request was served from a slave without opening a connection to the
+ # If this entire request was served from a slave without opening a connection to the
# master (however unlikely that may be), then we can fetch the position from the slave.
if ( empty( $this->mConnections[0] ) ) {
$conn =& $this->getConnection( DB_SLAVE );
}
return array( $host, $maxLag );
}
-
+
/**
* Get lag time for each DB
* Results are cached for a short time in memcached
#
# Copyright (C) 2002, 2004 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
'log_params' => $this->params
), $fname
);
-
+
# And update recentchanges
if ( $this->updateRecentChanges ) {
$titleObj = Title::makeTitle( NS_SPECIAL, 'Log/' . $this->type );
else
$rcComment .= ': ' . $this->comment;
}
-
+
RecentChange::notifyLog( $now, $titleObj, $wgUser, $rcComment );
}
return true;
wfRunHooks( 'LogPageValidTypes', array( &$types) );
return $types;
}
-
+
/**
* @static
*/
);
return $actions[$type];
}
-
+
/**
* @static
*/
function isLogType( $type ) {
return in_array( $type, LogPage::validTypes() );
}
-
+
/**
* @static
*/
return str_replace( '_', ' ', wfMsg( $typeText[$type] ) );
}
-
+
/**
* @static
*/
return wfMsg( $headerText[$type] );
}
-
+
/**
* @static
*/
$key = "$type/$action";
if( isset( $actions[$key] ) ) {
if( is_null( $title ) ) {
- $rv=wfMsgForContent( $actions[$key] );
+ $rv=wfMsg( $actions[$key] );
} else {
if( $skin ) {
if ( $type == 'move' ) {
$titleLink = $title->getPrefixedText();
}
if( count( $params ) == 0 ) {
- $rv = wfMsgForContent( $actions[$key], $titleLink );
+ $rv = wfMsg( $actions[$key], $titleLink );
} else {
array_unshift( $params, $titleLink );
- $rv = wfMsgReal( $actions[$key], $params, true, true );
+ $rv = wfMsgReal( $actions[$key], $params, true, false );
}
}
} else {
if ( !is_array( $params ) ) {
$params = array( $params );
}
-
+
$this->action = $action;
$this->target =& $target;
$this->comment = $comment;
$this->params = LogPage::makeParamBlob( $params );
-
+
$this->actionText = LogPage::actionText( $this->type, $action, $target, NULL, $params );
return $this->saveContent();
}
- /**
+ /**
* Create a blob from a parameter array
* @static
*/
* Provide things related to namespaces
* @package MediaWiki
*/
-
+
/**
* This is not a valid entry point, perform no further processing unless MEDIAWIKI is defined
*/
if( defined( 'MEDIAWIKI' ) ) {
-
+
/**
* Definitions of the NS_ constants are in Defines.php
* @private
* @return bool
*/
function isMovable( $index ) {
- if ( $index < NS_MAIN || $index == NS_IMAGE || $index == NS_CATEGORY ) {
- return false;
+ if ( $index < NS_MAIN || $index == NS_IMAGE || $index == NS_CATEGORY ) {
+ return false;
}
return true;
}
return ( $index == NS_TALK || $index == NS_USER_TALK ||
$index == NS_PROJECT_TALK || $index == NS_IMAGE_TALK ||
$index == NS_MEDIAWIKI_TALK || $index == NS_TEMPLATE_TALK ||
- $index == NS_HELP_TALK || $index == NS_CATEGORY_TALK
+ $index == NS_HELP_TALK || $index == NS_CATEGORY_TALK
|| ( (isset($wgExtraNamespaces) && $index % 2) )
);
-
+
}
/**
}
if ( $type == CACHE_MEMCACHED ) {
- if ( !array_key_exists( CACHE_MEMCACHED, $wgCaches ) ){
+ if ( !array_key_exists( CACHE_MEMCACHED, $wgCaches ) ){
require_once( 'memcached-client.php' );
-
+
if (!class_exists("MemcachedClientforWiki")) {
class MemCachedClientforWiki extends memcached {
function _debugprint( $text ) {
}
}
- $wgCaches[CACHE_DB] = new MemCachedClientforWiki(
+ $wgCaches[CACHE_DB] = new MemCachedClientforWiki(
array('persistant' => false, 'compress_threshold' => 1500 ) );
$cache =& $wgCaches[CACHE_DB];
$cache->set_servers( $wgMemCachedServers );
}
$cache =& $wgCaches[CACHE_DB];
}
-
+
if ( $cache === false ) {
if ( !array_key_exists( CACHE_NONE, $wgCaches ) ) {
$wgCaches[CACHE_NONE] = new FakeMemCachedClient;
$fname = 'PageHistory::history';
wfProfileIn( $fname );
+ $dbr = wfGetDB(DB_SLAVE);
+
/*
* Setup page variables.
*/
/* Offset must be an integral. */
if (!strlen($offset) || !preg_match("/^[0-9]+$/", $offset))
$offset = 0;
-
+# $offset = $dbr->timestamp($offset);
+ $dboffset = $dbr->timestamp($offset);
+wfdebug("offset=[$offset] dboffset=[$dboffset]\n");
/*
* "go=last" means to jump to the last history page.
*/
case "first":
if (($lastid = $this->getLastOffsetForPaging($id, $limit)) === NULL)
break;
- $gourl = $wgTitle->getLocalURL("action=history&limit={$limit}&offset={$lastid}");
+ $gourl = $wgTitle->getLocalURL("action=history&limit={$limit}&offset=".
+ wfTimestamp(TS_MW, $lastid));
break;
default:
$gourl = NULL;
* previous revisions when generating the URL.
*/
$direction = $this->getDirection();
- $revisions = $this->fetchRevisions($limit, $offset, $direction);
+ $revisions = $this->fetchRevisions($limit, $dboffset, $direction);
$navbar = $this->makeNavbar($revisions, $offset, $limit, $direction);
/*
/** @todo document */
function revLink( $row ) {
global $wgUser, $wgLang;
- $date = $wgLang->timeanddate( $row->rev_timestamp, true );
+ $date = $wgLang->timeanddate( wfTimestamp(TS_MW, $row->rev_timestamp), true );
if( $row->rev_deleted && !$wgUser->isAllowed( 'undelete' ) ) {
return $date;
} else {
$db =& wfGetDB(DB_SLAVE);
$revision = $db->tableName( 'revision' );
$sql = "SELECT rev_timestamp FROM $revision WHERE rev_page = $id " .
- "ORDER BY rev_timestamp ASC LIMIT $step";
+ "ORDER BY rev_timestamp ASC";
+ $sql = $db->limitResult($sql, $step, 0);
$res = $db->query( $sql, "PageHistory::getLastOffsetForPaging" );
$n = $db->numRows( $res );
if ($offset)
$offsets .= " AND rev_timestamp $oper '$offset' ";
- if ($limit)
- $limits .= " LIMIT $limitplus ";
$page_id = $this->mTitle->getArticleID();
$sql = "SELECT rev_id,rev_user," .
"FROM $revision $use_index " .
"WHERE rev_page=$page_id " .
$offsets .
- "ORDER BY rev_timestamp $dirs " .
- $limits;
+ "ORDER BY rev_timestamp $dirs ";
+ if ($limit)
+ $sql = $db->limitResult($sql, $limitplus, 0);
$res = $db->query($sql, "PageHistory::fetchRevisions");
$result = array();
$revisions = array_slice($revisions, 0, $limit);
$pageid = $this->mTitle->getArticleID();
- $latestTimestamp = $this->getLatestOffset( $pageid );
- $earliestTimestamp = $this->getEarliestOffset( $pageid );
+ $latestTimestamp = wfTimestamp(TS_MW, $this->getLatestOffset( $pageid ));
+ $earliestTimestamp = wfTimestamp(TS_MW, $this->getEarliestOffset( $pageid ));
/*
* When we're displaying previous revisions, we need to reverse
$lowts = $hights = 0;
if( count( $revisions ) ) {
- $latestShown = $revisions[0]->rev_timestamp;
- $earliestShown = $revisions[count($revisions) - 1]->rev_timestamp;
+ $latestShown = wfTimestamp(TS_MW, $revisions[0]->rev_timestamp);
+ $earliestShown = wfTimestamp(TS_MW, $revisions[count($revisions) - 1]->rev_timestamp);
}
$firsturl = $wgTitle->escapeLocalURL("action=history&limit={$limit}&go=first");
$firsttext = wfMsgHtml('histfirst');
$lasttext = wfMsgHtml('histlast');
- $prevurl = $wgTitle->escapeLocalURL("action=history&dir=prev&offset={$latestShown}&limit={$limit}");
- $nexturl = $wgTitle->escapeLocalURL("action=history&offset={$earliestShown}&limit={$limit}");
+ $prevurl = $wgTitle->escapeLocalURL("action=history&dir=prev&offset=$latestShown&limit={$limit}");
+ $nexturl = $wgTitle->escapeLocalURL("action=history&offset=$earliestShown&limit={$limit}");
$urls = array();
foreach (array(20, 50, 100, 250, 500) as $num) {
$urls[] = "<a href=\"".$wgTitle->escapeLocalURL(
- "action=history&offset={$offset}&limit={$num}")."\">".$wgLang->formatNum($num)."</a>";
+ "action=history&offset=" . wfTimestamp(TS_MW, $offset) .
+ "&limit={$num}")."\">".$wgLang->formatNum($num)."</a>";
}
$bits = implode($urls, ' | ');
array( 'DeadendPagesPage', 'Deadendpages' ),
array( 'DisambiguationsPage', 'Disambiguations' ),
array( 'DoubleRedirectsPage', 'DoubleRedirects' ),
- array( 'ListUsersPage', 'Listusers' ),
+ array( 'ListUsersPage', 'Listusers' ),
array( 'LonelyPagesPage', 'Lonelypages' ),
array( 'LongPagesPage', 'Longpages' ),
array( 'NewPagesPage', 'Newpages' ),
function getPageHeader( ) {
return '';
}
-
+
/**
* If using extra form wheely-dealies, return a set of parameters here
* as an associative array. They will be encoded and added to the paging
function linkParameters() {
return array();
}
-
+
/**
* Some special pages (for example SpecialListusers) might not return the
* current object formatted, but return the previous one instead.
}
$querycache = $dbr->tableName( 'querycache' );
-
+
if ( $ignoreErrors ) {
$ignoreW = $dbw->ignoreErrors( true );
$ignoreR = $dbr->ignoreErrors( true );
$wgOut->addWikiText( wfMsg( 'perfcached' ) );
}
}
-
- $res = $dbr->query( $sql . $this->getOrder() .
- $dbr->limitResult( $limit,$offset ), $fname );
+
+ $sql = $dbr->limitResult($sql . $this->getOrder(), $limit, $offset);
+ $res = $dbr->query( $sql );
$num = $dbr->numRows($res);
-
+
$sk = $wgUser->getSkin( );
if($shownavigation) {
$wgOut->addHTML( $this->getPageHeader() );
$top = wfShowingResults( $offset, $num);
$wgOut->addHTML( "<p>{$top}\n" );
-
+
# often disable 'next' link when we reach the end
if($num < $limit) { $atend = true; } else { $atend = false; }
-
+
$sl = wfViewPrevNext( $offset, $limit ,
$wgContLang->specialPage( $sname ),
wfArrayToCGI( $this->linkParameters() ), $atend );
$s .= "<li{$attr}>{$format}</li>\n";
}
}
-
+
$dbr->freeResult( $res );
$s .= '</ol>';
$wgOut->addHTML( $s );
}
# Fixup database timestamps
- $this->mAttribs['rc_timestamp']=$dbw->timestamp($this->mAttribs['rc_timestamp']);
- $this->mAttribs['rc_cur_time']=$dbw->timestamp($this->mAttribs['rc_cur_time']);
+ $this->mAttribs['rc_timestamp'] = $dbw->timestamp($this->mAttribs['rc_timestamp']);
+ $this->mAttribs['rc_cur_time'] = $dbw->timestamp($this->mAttribs['rc_cur_time']);
+ $this->mAttribs['rc_id'] = $dbw->nextSequenceValue( 'rc_rc_id_seq' );
# Insert new row
$dbw->insert( 'recentchanges', $this->mAttribs, $fname );
function loadFromRow( $row )
{
$this->mAttribs = get_object_vars( $row );
+ $this->mAttribs["rc_timestamp"] = wfTimestamp(TS_MW, $this->mAttribs["rc_timestamp"]);
$this->mExtra = array();
}
function loadFromCurRow( $row )
{
$this->mAttribs = array(
- 'rc_timestamp' => $row->rev_timestamp,
+ 'rc_timestamp' => wfTimestamp(TS_MW, $row->rev_timestamp),
'rc_cur_time' => $row->rev_timestamp,
'rc_user' => $row->rev_user,
'rc_user_text' => $row->rev_user_text,
return Revision::newFromConds(
array( 'page_id=rev_page',
'rev_id' => IntVal( $id ) ) );
+ return $ret;
}
-
+
/**
* Load either the current, or a specified, revision
* that's attached to a given title. If not attached
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDbkey() ) );
}
-
+
/**
* Load either the current, or a specified, revision
* that's attached to a given page. If not attached
} else {
$matchId = 'page_latest';
}
- return Revision::loadFromConds(
+ $ret = Revision::loadFromConds(
$db,
array( "rev_id=$matchId",
'rev_page' => IntVal( $pageid ),
'page_id=rev_page' ) );
+ return $ret;
}
-
+
/**
* Load either the current, or a specified, revision
* that's attached to a given page. If not attached
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDbkey() ) );
}
-
+
/**
* Load the revision for the given title with the given timestamp.
* WARNING: Timestamps may in some circumstances not be unique,
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDbkey() ) );
}
-
+
/**
* Given a set of conditions, fetch a revision.
*
}
return $row;
}
-
+
/**
* Given a set of conditions, fetch a revision from
* the given database connection.
$row = $res->fetchObject();
$res->free();
if( $row ) {
- return new Revision( $row );
+ $ret = new Revision( $row );
+ return $ret;
}
}
- return null;
+ $ret = null;
+ return $ret;
}
-
+
/**
* Return a wrapper for a series of database rows to
* fetch all of a given page's revisions in turn.
wfGetDB( DB_SLAVE ),
array( 'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDbkey(),
- 'page_id=rev_page' ) );
+ 'page_id=rev_page' ) );
}
-
+
/**
* Return a wrapper for a series of database rows to
* fetch all of a given page's revisions in turn.
array( 'rev_id=page_latest',
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDbkey(),
- 'page_id=rev_page' ) );
+ 'page_id=rev_page' ) );
}
-
+
/**
* Given a set of conditions, return a ResultWrapper
* which will return matching database rows with the
$conditions,
'Revision::fetchRow',
array( 'LIMIT' => 1 ) );
- return $db->resultObject( $res );
+ $ret = $db->resultObject( $res );
+ return $ret;
}
-
+
/**
* @param object $row
* @access private
$this->mMinorEdit = IntVal( $row->rev_minor_edit );
$this->mTimestamp = $row->rev_timestamp;
$this->mDeleted = IntVal( $row->rev_deleted );
-
+
$this->mCurrent = ( $row->rev_id == $row->page_latest );
$this->mTitle = Title::makeTitle( $row->page_namespace,
$row->page_title );
-
+
if( isset( $row->old_text ) ) {
$this->mText = $this->getRevisionText( $row );
} else {
} elseif( is_array( $row ) ) {
// Build a new revision to be saved...
global $wgUser;
-
+
$this->mId = isset( $row['id'] ) ? IntVal( $row['id'] ) : null;
$this->mPage = isset( $row['page'] ) ? IntVal( $row['page'] ) : null;
$this->mTextId = isset( $row['text_id'] ) ? IntVal( $row['text_id'] ) : null;
$this->mMinorEdit = isset( $row['minor_edit'] ) ? IntVal( $row['minor_edit'] ) : 0;
$this->mTimestamp = isset( $row['timestamp'] ) ? StrVal( $row['timestamp'] ) : wfTimestamp( TS_MW );
$this->mDeleted = isset( $row['deleted'] ) ? IntVal( $row['deleted'] ) : 0;
-
+
// Enforce spacing trimming on supplied text
$this->mComment = isset( $row['comment'] ) ? trim( StrVal( $row['comment'] ) ) : null;
$this->mText = isset( $row['text'] ) ? rtrim( StrVal( $row['text'] ) ) : null;
-
+
$this->mTitle = null; # Load on demand if needed
$this->mCurrent = false;
} else {
wfDebugDieBacktrace( 'Revision constructor passed invalid row format.' );
}
}
-
+
/**#@+
* @access public
*/
-
+
/**
* @return int
*/
function getId() {
return $this->mId;
}
-
+
/**
* @return int
*/
function getTextId() {
return $this->mTextId;
}
-
+
/**
* Returns the title of the page associated with this entry.
* @return Title
}
return $this->mTitle;
}
-
+
/**
* @return int
*/
function getPage() {
return $this->mPage;
}
-
+
/**
* @return int
*/
function getUser() {
return $this->mUser;
}
-
+
/**
* @return string
*/
function getUserText() {
return $this->mUserText;
}
-
+
/**
* @return string
*/
function getComment() {
return $this->mComment;
}
-
+
/**
* @return bool
*/
function isMinor() {
return (bool)$this->mMinorEdit;
}
-
+
/**
* @return bool
*/
function isDeleted() {
return (bool)$this->mDeleted;
}
-
+
/**
* @return string
*/
}
return $this->mText;
}
-
+
/**
* @return string
*/
function getTimestamp() {
- return $this->mTimestamp;
+ return wfTimestamp(TS_MW, $this->mTimestamp);
}
-
+
/**
* @return bool
*/
function isCurrent() {
return $this->mCurrent;
}
-
+
/**
* @return Revision
*/
function getRevisionText( $row, $prefix = 'old_' ) {
$fname = 'Revision::getRevisionText';
wfProfileIn( $fname );
-
+
# Get data
$textField = $prefix . 'text';
$flagsField = $prefix . 'flags';
# as pages are saved if $wgCompressRevisions is set.
$text = gzinflate( $text );
}
-
+
if( in_array( 'object', $flags ) ) {
# Generic compressed storage
$obj = unserialize( $text );
$text = $obj->getText();
}
-
+
global $wgLegacyEncoding;
if( $wgLegacyEncoding && !in_array( 'utf-8', $flags ) ) {
# Old revisions kept around in a legacy encoding?
function compressRevisionText( &$text ) {
global $wgCompressRevisions;
$flags = array();
-
+
# Revisions not marked this way will be converted
# on load if $wgLegacyCharset is set in the future.
$flags[] = 'utf-8';
-
+
if( $wgCompressRevisions ) {
if( function_exists( 'gzdeflate' ) ) {
$text = gzdeflate( $text );
}
return implode( ',', $flags );
}
-
+
/**
* Insert a new revision into the database, returning the new revision ID
* number on success and dies horribly on failure.
function insertOn( &$dbw ) {
$fname = 'Revision::insertOn';
wfProfileIn( $fname );
-
+
$mungedText = $this->mText;
$flags = Revision::compressRevisionText( $mungedText );
-
+
# Record the text to the text table
if( !isset( $this->mTextId ) ) {
$old_id = $dbw->nextSequenceValue( 'text_old_id_val' );
);
$this->mTextId = $dbw->insertId();
}
-
+
# Record the edit in revisions
$rev_id = isset( $this->mId )
? $this->mId
'rev_deleted' => $this->mDeleted,
), $fname
);
-
- $this->mId = $dbw->insertId();
-
+
+ $this->mId = !is_null($rev_id) ? $rev_id : $dbw->insertId();
+
wfProfileOut( $fname );
return $this->mId;
}
-
+
/**
* Lazy-load the revision's text.
* Currently hardcoded to the 'text' table storage engine.
function loadText() {
$fname = 'Revision::loadText';
wfProfileIn( $fname );
-
+
$dbr =& wfGetDB( DB_SLAVE );
$row = $dbr->selectRow( 'text',
array( 'old_text', 'old_flags' ),
array( 'old_id' => $this->getTextId() ),
$fname);
-
+
if( !$row ) {
$dbw =& wfGetDB( DB_MASTER );
$row = $dbw->selectRow( 'text',
array( 'old_id' => $this->getTextId() ),
$fname);
}
-
+
$text = Revision::getRevisionText( $row );
wfProfileOut( $fname );
-
+
return $text;
}
function newNullRevision( &$dbw, $pageId, $summary, $minor ) {
$fname = 'Revision::newNullRevision';
wfProfileIn( $fname );
-
+
$current = $dbw->selectRow(
array( 'page', 'revision' ),
array( 'page_latest', 'rev_text_id' ),
'page_latest=rev_id',
),
$fname );
-
+
if( $current ) {
$revision = new Revision( array(
'page' => $pageId,
} else {
$revision = null;
}
-
+
wfProfileOut( $fname );
return $revision;
}
-
+
}
?>
var $searchTerms = array();
var $namespaces = array( 0 );
var $showRedirects = false;
-
+
/**
* Perform a full text search query and return a result set.
* If title searches are not supported or disabled, return null.
function searchTitle( $term ) {
return null;
}
-
+
/**
* If an exact title match can be find, or a very slightly close match,
* return the title. If no match, returns NULL.
if ( $title->getNamespace() == NS_USER ) {
return $title;
}
-
+
# Quoted term? Try without the quotes...
if( preg_match( '/^"([^"]+)"$/', $term, $matches ) ) {
return SearchEngine::getNearMatch( $matches[1] );
}
-
+
return NULL;
}
-
+
function legalSearchChars() {
return "A-Za-z_'0-9\\x80-\\xFF\\-";
}
$this->limit = IntVal( $limit );
$this->offset = IntVal( $offset );
}
-
+
/**
* Set which namespaces the search should include.
* Give an array of namespace index numbers.
function setNamespaces( $namespaces ) {
$this->namespaces = $namespaces;
}
-
+
/**
* Make a list of searchable namespaces and their canonical names.
* @return array
}
return $arr;
}
-
+
/**
* Return a 'cleaned up' search string
*
$search->setLimitOffset(0,0);
return $search;
}
-
+
/**
* Create or update the search index record for the given page.
* Title and text should be pre-processed.
function termMatches() {
return array();
}
-
+
function numRows() {
return 0;
}
-
+
/**
* Return true if results are included in this result set.
* @return bool
function hasResults() {
return false;
}
-
+
/**
* Some search modes return a total hit count for the query
* in the entire article database. This may include pages
function getTotalHits() {
return null;
}
-
+
/**
* Some search modes return a suggested alternate term if there are
* no exact hits. Returns true if there is one on this set.
function hasSuggestion() {
return false;
}
-
+
/**
* Some search modes return a suggested alternate term if there are
* no exact hits. Check hasSuggestion() first.
function getSuggestion() {
return '';
}
-
+
/**
* Fetches next search result, or false.
* @return SearchResult
function SearchResult( $row ) {
$this->mTitle = Title::makeTitle( $row->page_namespace, $row->page_title );
}
-
+
/**
* @return Title
* @access public
function getTitle() {
return $this->mTitle;
}
-
+
/**
* @return double or null if not supported
*/
function search( $term ) {
return null;
}
+ function setLimitOffset($l, $o) {}
+ function legalSearchChars() {}
+ function update() {}
+ function setnamespaces() {}
+ function searchtitle() {}
+ function searchtext() {}
}
}
}
}
-
+
function doUpdate() {
global $wgDBname;
$fname = 'SiteStatsUpdate::doUpdate';
$row = $dbw->selectRow( 'site_stats', '*', false, $fname );
$updates = '';
-
+
$this->appendUpdate( $updates, 'ss_total_views', $this->mViews );
$this->appendUpdate( $updates, 'ss_total_edits', $this->mEdits );
$this->appendUpdate( $updates, 'ss_good_articles', $this->mGood );
$res = $dbr->query( $sql, $fname );
$userRow = $dbr->fetchObject( $res );
$users = $userRow->total + $this->mUsers;
-
+
if ( $updates ) {
$updates .= ',';
}
$updates .= "ss_total_pages=$pages, ss_users=$users";
- } else {
+ } else {
$this->appendUpdate( $updates, 'ss_total_pages', $this->mPages );
$this->appendUpdate( $updates, 'ss_users', $this->mUsers );
}
}
if ( $updates ) {
$site_stats = $dbw->tableName( 'site_stats' );
- $sql = "UPDATE $site_stats SET $updates LIMIT 1";
+ $sql = $dbw->limitResultForUpdate("UPDATE $site_stats SET $updates", 1);
$dbw->query( $sql, $fname );
}
}
$n = $wgIP;
$tl = $this->makeKnownLinkObj( $wgUser->getTalkPage(),
- $wgContLang->getNsText( NS_TALK ) );
+ $wgLang->getNsText( NS_TALK ) );
$s .= $n . ' ('.$tl.')';
} else {
$n = $wgUser->getName();
$rt = $wgTitle->getPrefixedURL();
$tl = $this->makeKnownLinkObj( $wgUser->getTalkPage(),
- $wgContLang->getNsText( NS_TALK ) );
+ $wgLang->getNsText( NS_TALK ) );
$tl = " ({$tl})";
$content_actions = array();
if( $this->iscontent ) {
+ $subjpage = $this->mTitle->getSubjectPage();
+ $talkpage = $this->mTitle->getTalkPage();
$nskey = $this->getNameSpaceKey();
$content_actions[$nskey] = $this->tabAction(
- $this->mTitle->getSubjectPage(),
+ $subjpage,
$nskey,
!$this->mTitle->isTalkPage(),
'', true);
$content_actions['talk'] = $this->tabAction(
- $this->mTitle->getTalkPage(),
+ $talkpage,
'talk',
$this->mTitle->isTalkPage(),
'',
$out .= $this->showline ( $inpoint, $outpoint, $namespace, false );
}
$out .= '</table>';
-
$nsForm = $this->namespaceForm ( $namespace, '', false );
# Is there more?
/**
* @todo Document
- * @param string $from
+ * @param string $from
* @param integer $namespace (Default NS_MAIN)
*/
function showline( $inpoint, $outpoint, $namespace = NS_MAIN ) {
$queryparams = ($namespace ? "namespace=$namespace" : '');
$special = Title::makeTitle( NS_SPECIAL, 'Allpages/' . $inpoint );
$link = $special->escapeLocalUrl( $queryparams );
-
+
$out = wfMsg(
'alphaindexline',
"<a href=\"$link\">$inpointf</a></td><td><a href=\"$link\">",
$n = 0;
$out = '<table style="background: inherit;" border="0" width="100%">';
-
+
$namespaces = $wgContLang->getFormattedNamespaces();
while( ($n < $this->maxPerPage) && ($s = $dbr->fetchObject( $res )) ) {
$t = Title::makeTitle( $s->page_namespace, $s->page_title );
$out .= '</tr>';
}
$out .= '</table>';
-
+
if ( $including ) {
$out2 = '';
} else {
$sql = "SELECT rev_timestamp FROM $page, $revision $use_index " .
"WHERE page_id = rev_page AND rev_timestamp > '" . $this->offset . "' AND " .
- "rev_user_text = " . $this->dbr->addQuotes($this->username) .
- $nscond;
- $sql .= " ORDER BY rev_timestamp ASC LIMIT " . ($this->limit+1);
+ "rev_user_text = " . $this->dbr->addQuotes($this->username)
+ . $nscond
+ $sql .= " ORDER BY rev_timestamp ASC";
+ $sql = $this->dbr->limitResult($sql, $this->limit, 0);
$res = $this->dbr->query($sql);
$rows = array();
while ($obj = $this->dbr->fetchObject($res))
$nscond = $this->get_namespace_cond();
$sql = "SELECT rev_timestamp FROM $page, $revision $use_index " .
"WHERE page_id = rev_page AND " .
- "rev_user_text = " . $this->dbr->addQuotes($this->username) .
- $nscond;
- $sql .= " ORDER BY rev_timestamp ASC LIMIT " . $this->limit;
+ "rev_user_text = " . $this->dbr->addQuotes($this->username)
+ . $nscond
+ $sql .= " ORDER BY rev_timestamp ASC";
+ $sql = $this->dbr->limitResult($sql, $this->limit + 1, 0);
$res = $this->dbr->query($sql);
$rows = array();
while ($obj = $this->dbr->fetchObject($res))
rev_deleted
FROM $page,$revision $use_index
WHERE page_id=rev_page AND $userCond $nscond $offsetQuery
- ORDER BY rev_timestamp DESC $limitQuery";
+ ORDER BY rev_timestamp DESC";
+ $sql = $this->dbr->limitResult($sql, $this->limit, 0);
return $sql;
}
$histlink='('.$sk->makeKnownLinkObj( $page, $messages['hist'], 'action=history' ) . ')';
$comment = $sk->commentBlock( $row->rev_comment, $page );
- $d = $wgLang->timeanddate( $row->rev_timestamp, true );
+ $d = $wgLang->timeanddate( wfTimestamp(TS_MW, $row->rev_timestamp), true );
if( $row->rev_minor_edit ) {
$mflag = '<span class="minor">' . $messages['minoreditletter'] . '</span> ';
<?php
# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
-#
+#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
class LogReader {
var $db, $joinClauses, $whereClauses;
var $type = '', $user = '', $title = null;
-
+
/**
* @param WebRequest $request For internal use use a FauxRequest object to pass arbitrary parameters.
*/
$this->db =& wfGetDB( DB_SLAVE );
$this->setupQuery( $request );
}
-
+
/**
* Basic setup and applies the limiting factors from the WebRequest object.
* @param WebRequest $request
$user = $this->db->tableName( 'user' );
$this->joinClauses = array( "LEFT OUTER JOIN $page ON log_namespace=page_namespace AND log_title=page_title" );
$this->whereClauses = array( 'user_id=log_user' );
-
+
$this->limitType( $request->getVal( 'type' ) );
$this->limitUser( $request->getText( 'user' ) );
$this->limitTitle( $request->getText( 'page' ) );
$this->limitTime( $request->getVal( 'from' ), '>=' );
$this->limitTime( $request->getVal( 'until' ), '<=' );
-
+
list( $this->limit, $this->offset ) = $request->getLimitOffset();
}
-
+
/**
* Set the log reader to return only entries of the given type.
* @param string $type A log type ('upload', 'delete', etc)
$safetype = $this->db->strencode( $type );
$this->whereClauses[] = "log_type='$safetype'";
}
-
+
/**
* Set the log reader to return only entries by the given user.
* @param string $name Valid user name
$user = $this->db->tableName( 'user' );
$this->whereClauses[] = "user_name='$safename'";
}
-
+
/**
* Set the log reader to return only entries affecting the given page.
* (For the block and rights logs, this is a user page.)
$ns = $title->getNamespace();
$this->whereClauses[] = "log_namespace=$ns AND log_title='$safetitle'";
}
-
+
/**
* Set the log reader to return only entries in a given time range.
* @param string $time Timestamp of one endpoint
$safetime = $this->db->strencode( wfTimestamp( TS_MW, $time ) );
$this->whereClauses[] = "log_timestamp $direction '$safetime'";
}
-
+
/**
* Build an SQL query from all the set parameters.
* @return string the SQL query
$sql .= " WHERE " . implode( ' AND ', $this->whereClauses );
}
$sql .= " ORDER BY log_timestamp DESC ";
- $sql .= $this->db->limitResult( $this->limit, $this->offset );
+ $sql = $this->db->limitResult( $sql, $this->limit, $this->offset );
return $sql;
}
-
+
/**
* Execute the query and start returning results.
* @return ResultWrapper result object to return the relevant rows
*/
function getRows() {
- return $this->db->resultObject( $this->db->query( $this->getQuery() ) );
+ $res = $this->db->query( $this->getQuery() );
+ return $this->db->resultObject( $res );
}
-
+
/**
* @return string The query type that this LogReader has been limited to.
*/
function queryType() {
return $this->type;
}
-
+
/**
* @return string The username type that this LogReader has been limited to, if any.
*/
function queryUser() {
return $this->user;
}
-
+
/**
* @return string The text of the title that this LogReader has been limited to.
*/
*/
var $reader;
var $numResults = 0;
-
+
/**
* @param LogReader &$reader where to get our data from
*/
$this->skin =& $wgUser->getSkin();
$this->reader =& $reader;
}
-
+
/**
* Take over the whole output page in $wgOut with the log display.
*/
* Load the data from the linked LogReader
* Preload the link cache
* Initialise numResults
- *
+ *
* Must be called before calling showPrevNext
*
* @return object database result set
return $result;
}
-
+
/**
* Output just the list of entries given by the linked LogReader,
* with extraneous UI elements. Use for displaying log fragments in
function showList( &$out ) {
$this->doShowList( $out, $this->getLogRows() );
}
-
+
function doShowList( &$out, $result ) {
// Rewind result pointer and go through it again, making the HTML
$html='';
$result->free();
$out->addHTML( $html );
}
-
+
/**
* @param Object $s a single row from the result set
* @return string Formatted HTML list item
global $wgLang, $wgLinkCache;
$title = Title::makeTitle( $s->log_namespace, $s->log_title );
$user = Title::makeTitleSafe( NS_USER, $s->user_name );
- $time = $wgLang->timeanddate( $s->log_timestamp, true );
+ $time = $wgLang->timeanddate( wfTimestamp(TS_MW, $s->log_timestamp), true );
// Enter the existence or non-existence of this page into the link cache,
// for faster makeLinkObj() in LogPage::actionText()
} else {
$wgLinkCache->addBadLinkObj( $title );
}
-
+
$userLink = $this->skin->makeLinkObj( $user, htmlspecialchars( $s->user_name ) );
$comment = $this->skin->commentBlock( $s->log_comment );
$paramArray = LogPage::extractParams( $s->log_params );
$destTitle = Title::newFromText( $paramArray[0] );
if ( $destTitle ) {
$revert = '(' . $this->skin->makeKnownLinkObj( $specialTitle, wfMsg( 'revertmove' ),
- 'wpOldTitle=' . urlencode( $destTitle->getPrefixedDBkey() ) .
+ 'wpOldTitle=' . urlencode( $destTitle->getPrefixedDBkey() ) .
'&wpNewTitle=' . urlencode( $title->getPrefixedDBkey() ) .
'&wpReason=' . urlencode( wfMsgForContent( 'revertmove' ) ) .
'&wpMovetalk=0' ) . ')';
$out = "<li>$time $userLink $action $comment $revert</li>\n";
return $out;
}
-
+
/**
* @param OutputPage &$out where to send output
* @private
$out->addWikiText( LogPage::logHeader( $type ) );
}
}
-
+
/**
* @param OutputPage &$out where to send output
* @private
"<input type='submit' value=\"" . wfMsg( 'allpagessubmit' ) . "\" />" .
"</form>" );
}
-
+
/**
* @return string Formatted HTML
* @private
$out .= "</select>\n";
return $out;
}
-
+
/**
* @return string Formatted HTML
* @private
$user = htmlspecialchars( $this->reader->queryUser() );
return wfMsg('specialloguserlabel') . "<input type='text' name='user' size='12' value=\"$user\" />\n";
}
-
+
/**
* @return string Formatted HTML
* @private
$title = htmlspecialchars( $this->reader->queryTitle() );
return wfMsg('speciallogtitlelabel') . "<input type='text' name='page' size='20' value=\"$title\" />\n";
}
-
+
/**
* @param OutputPage &$out where to send output
* @private
$pieces[] = 'page=' . urlencode( $this->reader->queryTitle() );
$bits = implode( '&', $pieces );
list( $limit, $offset ) = $wgRequest->getLimitOffset();
-
+
# TODO: use timestamps instead of offsets to make it more natural
# to go huge distances in time
$html = wfViewPrevNext( $offset, $limit,
$checked = $wgUser->getOption( $tname ) == 1 ? ' checked="checked"' : '';
$trailer = $trailer ? $trailer : '';
return "<div class='toggle'><input type='checkbox' value='1' id=\"$tname\" name=\"wpOp$tname\"$checked />" .
- " <span class='toggletext'><label for=\"$tname\">$ttext</label>$trailer</span></div>";
+ " <span class='toggletext'><label for=\"$tname\">$ttext</label>$trailer</span></div>\n";
}
function getToggles( $items ) {
<option value=\"1\"$s1>$msgUnderlinealways</option>
<option value=\"2\"$s2>$msgUnderlinedefault</option>
</select>
-</label></div>
+</label>
");
foreach ( $togs as $tname ) {
if( !array_key_exists( $tname, $this->mUsedToggles ) ) {
/**
* Constructor
*
- * @param string $par the namespace to get a random page from (default NS_MAIN),
+ * @param string $par the namespace to get a random page from (default NS_MAIN),
* used as e.g. Special:Randompage/Category
*/
function wfSpecialRandompage( $par = NS_MAIN ) {
if ($namespace === false || $namespace < NS_MAIN) {
$namespace = NS_MAIN;
}
-
+
# NOTE! We use a literal constant in the SQL instead of the RAND()
# function because RAND() will return a different value for every row
# in the table. That's both very slow and returns results heavily
#
# Using a literal constant means the whole thing gets optimized on
# the index, and the comparison is both fast and fair.
-
+
# interpolation and sprintf() can muck up with locale-specific decimal separator
$randstr = wfRandom();
-
+
$db =& wfGetDB( DB_SLAVE );
$use_index = $db->useIndexClause( 'page_random' );
$page = $db->tableName( 'page' );
FROM $page $use_index
WHERE page_namespace=$namespace AND page_is_redirect=0 $extra
AND page_random>$randstr
- ORDER BY page_random
- LIMIT 1";
+ ORDER BY page_random";
+ $sql = $db->limitResult($sql, 1, 0);
$res = $db->query( $sql, $fname );
-
+
$title = null;
if( $s = $db->fetchObject( $res ) ) {
$title =& Title::makeTitle( $namespace, $s->page_title );
- }
+ }
if( is_null( $title ) ) {
# That's not supposed to happen :)
$title = Title::newFromText( wfMsg( 'mainpage' ) );
);
extract($defaults);
-
+
$days = $wgUser->getOption( 'rcdays' );
if ( !$days ) { $days = $defaults['days']; }
$limit = $wgRequest->getInt( 'limit', $limit );
/* order of selection: url > preferences > default */
- $hideminor = $wgRequest->getBool( 'hideminor', $wgUser->getOption( 'hideminor') ? true : $defaults['hideminor'] );
+ $hideminor = $wgRequest->getBool( 'hideminor', $wgUser->getOption( 'hideminor') ? true : $defaults['hideminor'] );
+
-
# As a feed, use limited settings only
if( $feedFormat ) {
global $wgFeedLimit;
$hidebots = $wgRequest->getBool( 'hidebots', $defaults['hidebots'] );
$hideliu = $wgRequest->getBool( 'hideliu', $defaults['hideliu'] );
$hidepatrolled = $wgRequest->getBool( 'hidepatrolled', $defaults['hidepatrolled'] );
- $from = $wgRequest->getVal( 'from', $defaults['from'] );
+ $from = $wgRequest->getVal( 'from', $defaults['from'] );
# Get query parameters from path
if( $par ) {
$dbr =& wfGetDB( DB_SLAVE );
extract( $dbr->tableNames( 'recentchanges', 'watchlist' ) );
-
+
$cutoff_unixtime = time() - ( $days * 86400 );
$cutoff_unixtime = $cutoff_unixtime - ($cutoff_unixtime % 86400);
$cutoff = $dbr->timestamp( $cutoff_unixtime );
} else {
$from = $defaults['from'];
}
-
+
# 10 seconds server-side caching max
$wgOut->setSquidMaxage( 10 );
$uid = $wgUser->getID();
// Perform query
- $sql2 = "SELECT *" . ($uid ? ",wl_user,wl_notificationtimestamp" : "") . " FROM $recentchanges " .
+ $sql2 = "SELECT * FROM $recentchanges " .
($uid ? "LEFT OUTER JOIN $watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace " : "") .
"WHERE rc_timestamp > '{$cutoff}' {$hidem} " .
- "ORDER BY rc_timestamp DESC LIMIT {$limit}";
+ "ORDER BY rc_timestamp DESC";
+ $sql2 = $dbr->limitResult($sql2, $limit, 0);
$res = $dbr->query( $sql2, $fname );
// Fetch results, prepare a batch link existence check query
// Output header
if ( !$specialPage->including() ) {
$wgOut->addWikiText( wfMsgForContent( "recentchangestext" ) );
-
+
// Dump everything here
$nondefaults = array();
function rcOutputFeed( $rows, $feedFormat, $limit, $hideminor, $lastmod ) {
global $messageMemc, $wgDBname, $wgFeedCacheTimeout;
global $wgFeedClasses, $wgTitle, $wgSitename, $wgContLanguageCode;
-
+
if( !isset( $wgFeedClasses[$feedFormat] ) ) {
wfHttpError( 500, "Internal Server Error", "Unsupported feed type." );
return false;
}
-
+
$timekey = "$wgDBname:rcfeed:$feedFormat:timestamp";
$key = "$wgDBname:rcfeed:$feedFormat:limit:$limit:minor:$hideminor";
-
+
$feedTitle = $wgSitename . ' - ' . wfMsgForContent( 'recentchanges' ) .
' [' . $wgContLanguageCode . ']';
$feed = new $wgFeedClasses[$feedFormat](
rcDoOutputFeed( $rows, $feed );
$cachedFeed = ob_get_contents();
ob_end_flush();
-
+
$expire = 3600 * 24; # One day
$messageMemc->set( $key, $cachedFeed );
$messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire );
function rcDoOutputFeed( $rows, &$feed ) {
global $wgSitename, $wgFeedClasses, $wgContLanguageCode;
-
+
$feed->outHeader();
-
+
# Merge adjacent edits by one user
$sorted = array();
$n = 0;
}
$first = false;
}
-
+
foreach( $sorted as $obj ) {
$title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title );
$talkpage = $title->getTalkPage();
array( 'hidepatrolled' => 1-$options['hidepatrolled'] ), $nondefaults);
$hl = wfMsg( 'showhideminor', $minorLink, $botLink, $liuLink, $patrLink );
-
+
// show from this onward link
$now = $wgLang->timeanddate( wfTimestampNow(), true );
$tl = makeOptionsLink( $now, array( 'from' => wfTimestampNow()), $nondefaults );
-
+
$rclinks = wfMsg( 'rclinks', $cl, $dl, $hl );
$rclistfrom = wfMsg( 'rclistfrom', $tl );
return "$note<br />$rclinks<br />$rclistfrom";
function rcFormatDiff( $row ) {
$fname = 'rcFormatDiff';
wfProfileIn( $fname );
-
+
require_once( 'DifferenceEngine.php' );
$comment = "<p>" . htmlspecialchars( $row->rc_comment ) . "</p>\n";
-
+
if( $row->rc_namespace >= 0 ) {
global $wgContLang;
-
+
#$diff =& new DifferenceEngine( $row->rc_this_oldid, $row->rc_last_oldid, $row->rc_id );
#$diff->showDiffPage();
-
+
$titleObj = Title::makeTitle( $row->rc_namespace, $row->rc_title );
$dbr =& wfGetDB( DB_SLAVE );
$newrev =& Revision::newFromTitle( $titleObj, $row->rc_this_oldid );
return $comment . $diffText;
}
$oldtext = $oldrev->getText();
-
+
# Old entries may contain illegal characters
# which will damage output
$oldtext = UtfNormal::cleanUp( $oldtext );
-
+
global $wgFeedDiffCutoff;
if( strlen( $newtext ) > $wgFeedDiffCutoff ||
strlen( $oldtext ) > $wgFeedDiffCutoff ) {
}
wfProfileOut( "$fname-dodiff" );
} else {
- $diffText = '<p><b>' . wfMsg( 'newpage' ) . '</b></p>' .
+ $diffText = '<p><b>' . wfMsg( 'newpage' ) . '</b></p>' .
'<div>' . nl2br( htmlspecialchars( $newtext ) ) . '</div>';
}
-
+
wfProfileOut( $fname );
return $comment . $diffText;
}
-
+
wfProfileOut( $fname );
- return $comment;
+ return $comment;
}
?>
*/
class PageArchive {
var $title;
-
+
function PageArchive( &$title ) {
if( is_null( $title ) ) {
wfDebugDieBacktrace( 'Archiver() given a null title.');
}
$this->title =& $title;
}
-
+
/**
* List all deleted pages recorded in the archive table. Returns result
* wrapper with (ar_namespace, ar_title, count) fields, ordered by page
$dbr =& wfGetDB( DB_SLAVE );
$archive = $dbr->tableName( 'archive' );
- $sql = "SELECT ar_namespace,ar_title, COUNT(*) AS count FROM $archive " .
+ $sql = "SELECT ar_namespace,ar_title, COUNT(*) AS count FROM $archive " .
"GROUP BY ar_namespace,ar_title ORDER BY ar_namespace,ar_title";
return $dbr->resultObject( $dbr->query( $sql, 'PageArchive::listAllPages' ) );
}
-
+
/**
* List the revisions of the given page. Returns result wrapper with
* (ar_minor_edit, ar_timestamp, ar_user, ar_user_text, ar_comment) fields.
*/
function listRevisions() {
$dbr =& wfGetDB( DB_SLAVE );
- return $dbr->resultObject( $dbr->select( 'archive',
+ $res = $dbr->select( 'archive',
array( 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text', 'ar_comment' ),
array( 'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey() ),
'PageArchive::listRevisions',
- array( 'ORDER BY' => 'ar_timestamp DESC' ) ) );
+ array( 'ORDER BY' => 'ar_timestamp DESC' ) );
+ $ret = $dbr->resultObject( $res );
+ return $ret;
}
-
+
/**
* Fetch (and decompress if necessary) the stored text for the deleted
* revision of the page with the given timestamp.
return Revision::getRevisionText( $text );
}
}
-
+
/**
* Fetch (and decompress if necessary) the stored text of the most
* recently edited deleted revision of the page.
return NULL;
}
}
-
+
/**
* Quick check if any archived revisions are present for the page.
* @return bool
'ar_title' => $this->title->getDBkey() ) );
return ($n > 0);
}
-
+
/**
* This is the meaty bit -- restores archived revisions of the given page
* to the cur/old tables. If the page currently exists, all revisions will
$previousRevId = 0;
$previousTimestamp = 0;
}
-
+
if( $restoreAll ) {
- $oldones = '1'; # All revisions...
+ $oldones = '1 = 1'; # All revisions...
} else {
$oldts = implode( ',',
array_map( array( &$dbw, 'addQuotes' ),
array_map( array( &$dbw, 'timestamp' ),
$timestamps ) ) );
-
+
$oldones = "ar_timestamp IN ( {$oldts} )";
}
-
+
/**
* Restore each revision...
*/
) );
$revision->insertOn( $dbw );
}
-
+
if( $revision ) {
# FIXME: Update latest if newer as well...
if( $newid ) {
# FIXME: update article count if changed...
$article->updateRevisionOn( $dbw, $revision, $previousRevId );
-
+
# Finally, clean up the link tables
$wgLinkCache = new LinkCache();
# Select for update
$wgLinkCache->forUpdate( true );
-
+
# Create a dummy OutputPage to update the outgoing links
$dummyOut = new OutputPage();
$dummyOut->addWikiText( $revision->getText() );
$u = new LinksUpdate( $newid, $this->title->getPrefixedDBkey() );
array_push( $wgDeferredUpdateList, $u );
-
+
#TODO: SearchUpdate, etc.
}
-
+
if( $newid ) {
Article::onArticleCreate( $this->title );
} else {
'ar_title' => $this->title->getDBkey(),
$oldones ),
$fname );
-
+
# Touch the log!
$log = new LogPage( 'delete' );
if( $restoreAll ) {
/* private */ function showList() {
global $wgLang, $wgContLang, $wgUser, $wgOut;
$fname = "UndeleteForm::showList";
-
- # List undeletable articles
+
+ # List undeletable articles
$result = PageArchive::listAllPages();
-
+
$wgOut->setPagetitle( wfMsg( "undeletepage" ) );
$wgOut->addWikiText( wfMsg( "undeletepagetext" ) );
$undelete =& Title::makeTitle( NS_SPECIAL, 'Undelete' );
$wgOut->addHTML( "<ul>\n" );
while( $row = $result->fetchObject() ) {
- $n = ($row->ar_namespace ?
+ $n = ($row->ar_namespace ?
($wgContLang->getNsText( $row->ar_namespace ) . ":") : "").
$row->ar_title;
$link = $sk->makeKnownLinkObj( $undelete,
}
$result->free();
$wgOut->addHTML( "</ul>\n" );
-
+
return true;
}
-
+
/* private */ function showRevision( $timestamp ) {
global $wgLang, $wgUser, $wgOut;
$fname = "UndeleteForm::showRevision";
$archive =& new PageArchive( $this->mTargetObj );
$text = $archive->getRevisionText( $timestamp );
-
+
$wgOut->setPagetitle( wfMsg( "undeletepage" ) );
$wgOut->addWikiText( "(" . wfMsg( "undeleterevision",
$wgLang->date( $timestamp ) ) . ")\n<hr />\n" . $text );
/* private */ function showHistory() {
global $wgLang, $wgUser, $wgOut;
-
+
$sk = $wgUser->getSkin();
$wgOut->setPagetitle( wfMsg( "undeletepage" ) );
# List all stored revisions
$revisions = $archive->listRevisions();
-
+
$titleObj = Title::makeTitle( NS_SPECIAL, "Undelete" );
$action = $titleObj->escapeLocalURL( "action=submit" );
$encTarget = htmlspecialchars( $this->mTarget );
$button = htmlspecialchars( wfMsg("undeletebtn") );
$token = htmlspecialchars( $wgUser->editToken() );
-
+
$wgOut->addHTML("
<form id=\"undelete\" method=\"post\" action=\"{$action}\">
<input type=\"hidden\" name=\"target\" value=\"{$encTarget}\" />
array( 'page' => $this->mTargetObj->getPrefixedText(),
'type' => 'delete' ) ) ) );
$logViewer->showList( $wgOut );
-
+
# The page's stored (deleted) history:
$wgOut->addHTML( "<h2>" . htmlspecialchars( wfMsg( "history" ) ) . "</h2>\n" );
$wgOut->addHTML("<ul>");
$ts = wfTimestamp( TS_MW, $row->ar_timestamp );
$checkBox = "<input type=\"checkbox\" name=\"ts$ts\" value=\"1\" />";
$pageLink = $sk->makeKnownLinkObj( $titleObj,
- $wgLang->timeanddate( $row->ar_timestamp, true ),
+ $wgLang->timeanddate( $ts, true ),
"target=$target×tamp=$ts" );
$userLink = htmlspecialchars( $row->ar_user_text );
if( $row->ar_user ) {
}
$revisions->free();
$wgOut->addHTML("</ul>\n</form>");
-
+
return true;
}
return $t;
} else {
wfProfileOut( $fname );
- return NULL;
+ $ret = NULL;
+ return $ret;
}
}
*/
function getArticleID( $flags = 0 ) {
global $wgLinkCache;
-
if ( $flags & GAID_FOR_UPDATE ) {
$oldUpdate = $wgLinkCache->forUpdate( true );
$this->mArticleID = $wgLinkCache->addLinkObj( $this );
$this->mArticleID = $wgLinkCache->addLinkObj( $this );
}
}
+wfdebug("title: articleid = ".$this->mArticleID."\n");
return $this->mArticleID;
}
while( $row = $dbw->fetchObject( $res ) ) {
$toucharr[] = $row->pl_from;
}
-
+ if (!count($toucharr))
+ return;
$dbw->update( 'page', /* SET */ array( 'page_touched' => $dbw->timestamp() ),
/* WHERE */ array( 'page_id' => $toucharr ),$fname);
}
array( 'wl_title' => $this->getTitleKey(),
'wl_namespace' => NS_USER_TALK,
'wl_user' => $this->mId,
- 'wl_notificationtimestamp != 0' ),
+ 'wl_notificationtimestamp ' . $dbr->notNullTimestamp() ),
'User::getNewtalk' );
if( $dbr->numRows($res) > 0 ) {
$this->mNewtalk = 1;
$dbw =& wfGetDB( DB_MASTER );
$success = $dbw->update( 'watchlist',
array( /* SET */
- 'wl_notificationtimestamp' => 0
+ 'wl_notificationtimestamp' => NULL
), array( /* WHERE */
'wl_title' => $title->getDBkey(),
'wl_namespace' => $title->getNamespace(),
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* http://www.gnu.org/copyleft/gpl.html
- *
+ *
* @author <brion@pobox.com>
* @author <mail@tgries.de>
- *
+ *
* @package MediaWiki
*/
*/
function userMailer( $to, $from, $subject, $body, $replyto=false ) {
global $wgUser, $wgSMTP, $wgOutputEncoding, $wgErrorString, $wgEmergencyContact;
-
+
if (is_array( $wgSMTP )) {
require_once( 'Mail.php' );
-
+
$timestamp = time();
-
+
$headers['From'] = $from;
if ( $replyto ) {
$headers['Reply-To'] = $replyto;
$headers['Content-transfer-encoding'] = '8bit';
$headers['Message-ID'] = "<{$timestamp}" . $wgUser->getName() . '@' . $wgSMTP['IDHost'] . '>';
$headers['X-Mailer'] = 'MediaWiki mailer';
-
+
// Create the mail object using the Mail::factory method
$mail_object =& Mail::factory('smtp', $wgSMTP);
wfDebug( "Sending mail via PEAR::Mail\n" );
$mailResult =& $mail_object->send($to, $headers, $body);
-
- # Based on the result return an error string,
+
+ # Based on the result return an error string,
if ($mailResult === true)
return '';
else if (is_object($mailResult))
* same timeoffset in their preferences.
*
* Visit the documentation pages under http://meta.wikipedia.com/Enotif
- *
+ *
* @package MediaWiki
- *
+ *
*/
class EmailNotification {
/**#@+
*/
var $to, $subject, $body, $replyto, $from;
var $user, $title, $timestamp, $summary, $minorEdit, $oldid;
-
+
/**#@-*/
-
+
/**
* @todo document
* @param $currentPage
* @param $oldid (default: false)
*/
function notifyOnPageChange(&$title, $timestamp, $summary, $minorEdit, $oldid=false) {
-
+
# we use $wgEmergencyContact as sender's address
global $wgUser, $wgLang, $wgEmergencyContact;
global $wgEnotifWatchlist, $wgEnotifMinorEdits;
$fname = 'UserMailer::notifyOnPageChange';
wfProfileIn( $fname );
-
+
# The following code is only run, if several conditions are met:
# 1. EmailNotification for pages (other than user_talk pages) must be enabled
# 2. minor edits (changes) are only regarded if the global flag indicates so
-
+
$isUserTalkPage = ($title->getNamespace() == NS_USER_TALK);
$enotifusertalkpage = ($isUserTalkPage && $wgEnotifUserTalk);
- $enotifwatchlistpage = (!$isUserTalkPage && $wgEnotifWatchlist);
+ $enotifwatchlistpage = (!$isUserTalkPage && $wgEnotifWatchlist);
if ( ($enotifusertalkpage || $enotifwatchlistpage) && (!$minorEdit || $wgEnotifMinorEdits) ) {
$dbr =& wfGetDB( DB_MASTER );
extract( $dbr->tableNames( 'watchlist' ) );
- $res = $dbr->select( 'watchlist', array( 'wl_user' ),
+ $res = $dbr->select( 'watchlist', array( 'wl_user' ),
array(
'wl_title' => $title->getDBkey(),
'wl_namespace' => $title->getNamespace(),
'wl_user <> ' . $wgUser->getID(),
- 'wl_notificationtimestamp <= 1',
+ 'wl_notificationtimestamp ' . $dbr->isNullTimestamp(),
), $fname );
# if anyone is watching ... set up the email message text which is
# common for all receipients ...
- if ( $dbr->numRows( $res ) > 0 ) {
+ if ( $dbr->numRows( $res ) > 0 ) {
$this->user &= $wgUser;
$this->title =& $title;
$this->timestamp = $timestamp;
$this->composeCommonMailtext();
$watchingUser = new User();
-
+
# ... now do for all watching users ... if the options fit
- for ($i = 1; $i <= $dbr->numRows( $res ); $i++) {
+ for ($i = 1; $i <= $dbr->numRows( $res ); $i++) {
$wuser = $dbr->fetchObject( $res );
$watchingUser->setID($wuser->wl_user);
} # if $wgEnotifWatchlist = true
if ( $wgShowUpdatedMarker || $wgEnotifWatchlist ) {
- # mark the changed watch-listed page with a timestamp, so that the page is
+ # mark the changed watch-listed page with a timestamp, so that the page is
# listed with an "updated since your last visit" icon in the watch list, ...
$dbw =& wfGetDB( DB_MASTER );
$success = $dbw->update( 'watchlist',
array( /* SET */
- 'wl_notificationtimestamp' => $timestamp
+ 'wl_notificationtimestamp' => $dbw->timestamp($timestamp)
), array( /* WHERE */
'wl_title' => $title->getDBkey(),
'wl_namespace' => $title->getNamespace(),
}
} # function NotifyOnChange
-
+
/**
* @access private
*/
global $wgEnotifRevealEditorAddress;
global $wgEnotifFromEditor;
global $wgNoReplyAddress;
-
+
$summary = ($this->summary == '') ? ' - ' : $this->summary;
$medit = ($this->minorEdit) ? wfMsg( 'minoredit' ) : '';
-
+
# You as the WikiAdmin and Sysops can make use of plenty of
# named variables when composing your notification emails while
# simply editing the Meta pages
-
+
$subject = wfMsgForContent( 'enotif_subject' );
$body = wfMsgForContent( 'enotif_body' );
$from = ''; /* fail safe */
$replyto = ''; /* fail safe */
$keys = array();
-
+
# regarding the use of oldid as an indicator for the last visited version, see also
# http://bugzilla.wikipeda.org/show_bug.cgi?id=603 "Delete + undelete cycle doesn't preserve old_id"
# However, in the case of a new page which is already watched, we have no previous version to compare
$keys['$OLDID'] = '';
$keys['$CHANGEDORCREATED'] = wfMsgForContent( 'created' );
}
-
- $body = strtr( $body, $keys );
+
+ $body = strtr( $body, $keys );
$pagetitle = $this->title->getPrefixedText();
-
$keys['$PAGETITLE'] = $pagetitle;
$keys['$PAGETITLE_URL'] = $this->title->getFullUrl();
$keys['$PAGEMINOREDIT'] = $medit;
$keys['$PAGESUMMARY'] = $summary;
-
+
$subject = strtr( $subject, $keys );
# Reveal the page editor's address as REPLY-TO address only if
$from = $adminAddress;
$replyto = $wgNoReplyAddress;
}
-
+
if( $wgUser->isIP( $name ) ) {
#real anon (user:xxx.xxx.xxx.xxx)
$anon = $name . ' (anonymous user)';
$anonUrl = wfUrlencode( $name ) . ' (anonymous user)';
$subject = str_replace('$PAGEEDITOR', 'anonymous user '. $name, $subject);
-
+
$keys['$PAGEEDITOR'] = 'anonymous user ' . $name;
$keys['$PAGEEDITOR_EMAIL'] = wfMsgForContent( 'noemailtitle' );
} else {
$userPage = $wgUser->getUserPage();
$keys['$PAGEEDITOR_WIKI'] = $userPage->getFullUrl();
$body = strtr( $body, $keys );
-
$body = wordwrap( $body, 72 );
# now save this as the constant user-independent part of the message
}
-
+
/**
* Does the per-user customizations to a notification e-mail (name,
* timestamp in proper timezone, etc) and sends it out.
function composeAndSendPersonalisedMail( $watchingUser ) {
global $wgLang;
// From the PHP manual:
- // Note: The to parameter cannot be an address in the form of "Something <someone@example.com>".
+ // Note: The to parameter cannot be an address in the form of "Something <someone@example.com>".
// The mail command will not parse this properly while talking with the MTA.
$to = $watchingUser->getEmail();
$body = str_replace( '$WATCHINGUSERNAME', $watchingUser->getName() , $this->body );
-
+
$timecorrection = $watchingUser->getOption( 'timecorrection' );
if( !$timecorrection ) {
# fail safe - I prefer it. TomGries
$body = str_replace('$PAGEEDITDATE',
$wgLang->timeanddate( $this->timestamp, true, false, $timecorrection ),
$body);
-
+
$error = userMailer( $to, $this->from, $this->subject, $body, $this->replyto );
return ($error == '');
}
global $wgDBname;
return "$wgDBname:watchlist:user:$this->id:page:$this->ns:$this->ti";
}
-
+
/**
* Is mTitle being watched by mUser?
*/
$key = $this->watchKey();
$iswatched = $wgMemc->get( $key );
if( is_integer( $iswatched ) ) return $iswatched;
-
+
$dbr =& wfGetDB( DB_SLAVE );
- $res = $dbr->select( 'watchlist', 1, array( 'wl_user' => $this->id, 'wl_namespace' => $this->ns,
+ $res = $dbr->select( 'watchlist', 1, array( 'wl_user' => $this->id, 'wl_namespace' => $this->ns,
'wl_title' => $this->ti ), $fname );
$iswatched = ($dbr->numRows( $res ) > 0) ? 1 : 0;
$wgMemc->set( $key, $iswatched );
# accidentally reloads a watch-add operation.
$dbw =& wfGetDB( DB_MASTER );
$dbw->replace( 'watchlist', array(array('wl_user', 'wl_namespace', 'wl_title', 'wl_notificationtimestamp')),
- array(
+ array(
'wl_user' => $this->id,
'wl_namespace' => ($this->ns & ~1),
'wl_title' => $this->ti,
- 'wl_notificationtimestamp' => '0'
+ 'wl_notificationtimestamp' => NULL
), $fname );
# the following code compensates the new behaviour, introduced by the enotif patch,
'wl_user' => $this->id,
'wl_namespace' => ($this->ns | 1 ),
'wl_title' => $this->ti,
- 'wl_notificationtimestamp' => '0'
+ 'wl_notificationtimestamp' => NULL
), $fname );
global $wgMemc;
$success = false;
$dbw =& wfGetDB( DB_MASTER );
- $dbw->delete( 'watchlist',
- array(
- 'wl_user' => $this->id,
+ $dbw->delete( 'watchlist',
+ array(
+ 'wl_user' => $this->id,
'wl_namespace' => ($this->ns & ~1),
'wl_title' => $this->ti
), $fname
'wl_title' => $this->ti
), $fname
);
-
+
if ( $dbw->affectedRows() ) {
$success = true;
}
$dbw =& wfGetDB( DB_MASTER );
$watchlist = $dbw->tableName( 'watchlist' );
-
- $res = $dbw->select( 'watchlist', 'wl_user',
+
+ $res = $dbw->select( 'watchlist', 'wl_user',
array( 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ),
$fname, 'FOR UPDATE'
);
# We dare not turn output buffer _off_ since this will break completely
# if PHP is globally configured to run through a gzip filter.
@ob_implicit_flush( true );
-
+
if( !function_exists( 'version_compare' ) ) {
# version_compare was introduced in 4.1.0
die( "Your PHP version is much too old; 4.0.x will _not_ work. 4.3.2 or higher is recommended. ABORTING.\n" );
if( version_compare( phpversion(), '4.3.2' ) < 0 ) {
echo "WARNING: PHP 4.3.2 or higher is recommended. Older versions from 4.1.x up may work but are not actively supported.\n\n";
}
-
+
if (!extension_loaded('mysql')) {
if (!dl('mysql.so')) {
print 'Could not load MySQL driver! Please compile '.
exit;
}
}
-
+
global $wgCommandLineMode;
$wgCommandLineMode = true;
umask( 000 );
if ( $sl < 0 ) { continue; }
if ( '-' == $line{0} && '-' == $line{1} ) { continue; }
- if ( ';' == $line{$sl} ) {
+ if ( ';' == $line{$sl} && ($sl < 2 || ';' != $line{$sl - 1})) {
$done = true;
$line = substr( $line, 0, $sl );
}
if ( '' != $cmd ) { $cmd .= ' '; }
- $cmd .= $line;
+ $cmd .= "$line\n";
if ( $done ) {
+ $cmd = str_replace(';;', ";", $cmd);
$cmd = replacevars( $cmd );
if( $database )
- $res = $database->query( $cmd );
+ $res = $database->query( $cmd, 'dbsource', true );
else
$res = mysql_query( $cmd );
$db =& wfGetDB( DB_SLAVE );
$res = $db->query( "DESCRIBE $table", $fname );
$found = false;
-
+
while ( $row = $db->fetchObject( $res ) ) {
if ( $row->Field == $field ) {
$found = true;
$timestamp = wfTimestampNow();
#$sql = "SELECT cur_title,cur_is_new,cur_user_text FROM $cur WHERE cur_namespace=$ns AND cur_title IN(";
- $sql = "SELECT page_title,page_is_new,rev_user_text FROM $page, $revision WHERE
- page_namespace=$ns AND rev_page=page_id AND page_title IN(";
-
# Get keys from $wgAllMessagesEn, which is more complete than the local language
$first = true;
if ( $messageArray ) {
# SELECT all existing messages
# Can't afford to be locking all rows for update, this script can take quite a long time to complete
- foreach ( $sortedArray as $key => $enMsg ) {
- if ( $key == '' ) {
- continue; // Skip odd members
- }
- if ( $first ) {
- $first = false;
- } else {
- $sql .= ',';
+ $rows = array();
+ $nitems = count($sortedArray);
+ $maxitems = $dbr->maxListLen();
+ $pos = 0;
+ if ($maxitems)
+ $chunks = array_chunk($sortedArray, $maxitems);
+ else
+ $chucks = array($sortedArray);
+
+ foreach ($chunks as $chunk) {
+ $first = true;
+ $sql = "SELECT page_title,page_is_new,rev_user_text FROM $page, $revision WHERE
+ page_namespace=$ns AND rev_page=page_id AND page_title IN(";
+
+ foreach ( $chunk as $key => $enMsg ) {
+ if ( $key == '' ) {
+ continue; // Skip odd members
+ }
+ if ( $first ) {
+ $first = false;
+ } else {
+ $sql .= ',';
+ }
+ $titleObj = Title::newFromText( $wgContLang->ucfirst( $key ) );
+ $enctitle = $dbr->strencode($titleObj->getDBkey());
+ $sql .= "'$enctitle'";
}
- $titleObj = Title::newFromText( $wgContLang->ucfirst( $key ) );
- $enctitle = $dbr->strencode($titleObj->getDBkey());
- $sql .= "'$enctitle'";
- }
- $sql .= ')';
- $res = $dbr->query( $sql );
- $row = $dbr->fetchObject( $res );
+ $sql .= ')';
+ $res = $dbr->query( $sql );
+ while ($row = $dbr->fetchObject($res))
+ $rows[] = $row;
+ }
+
# Read the results into an array
# Decide whether or not each one needs to be overwritten
$existingTitles = array();
- while ( $row ) {
+ foreach ($rows as $row) {
if ( $row->rev_user_text != $username && $row->rev_user_text != 'Template namespace initialisation script' ) {
$existingTitles[$row->page_title] = 'keep';
} else {
$existingTitles[$row->page_title] = 'chuck';
}
-
- $row = $dbr->fetchObject( $res );
}
# Insert queries are done in one multi-row insert
/**
* Copyright (C) 2005 Brion Vibber <brion@pobox.com>
* http://www.mediawiki.org/
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
var $pageCount = 0;
var $revCount = 0;
var $dryRun = false;
-
+
function BackupReader() {
$this->stderr = fopen( "php://stderr", "wt" );
}
-
+
function reportPage( $page ) {
$this->pageCount++;
}
-
+
function handleRevision( $rev ) {
$title = $rev->getTitle();
+ if (!$title) {
+ return;
+ }
$display = $title->getPrefixedText();
$timestamp = $rev->getTimestamp();
#echo "$display $timestamp\n";
-
+
$this->revCount++;
$this->report();
-
+
if( !$this->dryRun ) {
call_user_func( $this->importCallback, $rev );
}
}
-
+
function report( $final = false ) {
if( $final xor ( $this->pageCount % $this->reportingInterval == 0 ) ) {
$this->showReport();
}
}
-
+
function showReport() {
if( $this->reporting ) {
$delta = wfTime() - $this->startTime;
$this->progress( "$this->pageCount ($rate pages/sec $revrate revs/sec)" );
}
}
-
+
function progress( $string ) {
fwrite( $this->stderr, $string . "\n" );
}
-
+
function importFromFile( $filename ) {
if( preg_match( '/\.gz$/', $filename ) ) {
$filename = 'compress.zlib://' . $filename;
$file = fopen( $filename, 'rt' );
$this->importFromHandle( $file );
}
-
+
function importFromStdin() {
$file = fopen( 'php://stdin', 'rt' );
$this->importFromHandle( $file );
}
-
+
function importFromHandle( $handle ) {
$this->startTime = wfTime();
-
+
$source = new ImportStreamSource( $handle );
$importer = new WikiImporter( $source );
-
+
$importer->setPageCallback( array( &$this, 'reportPage' ) );
$this->importCallback = $importer->setRevisionCallback(
array( &$this, 'handleRevision' ) );
-
+
$importer->doImport();
}
}
--- /dev/null
+CREATE TABLE transcache (
+ tc_url VARCHAR2(255) NOT NULL UNIQUE,
+ tc_contents CLOB,
+ tc_time TIMESTAMP NOT NULL
+);
--- /dev/null
+-- Based more or less on the public interwiki map from MeatballWiki
+-- Default interwiki prefixes...
+
+CALL add_interwiki('abbenormal','http://www.ourpla.net/cgi-bin/pikie.cgi?$1',0);
+CALL add_interwiki('acadwiki','http://xarch.tu-graz.ac.at/autocad/wiki/$1',0);
+CALL add_interwiki('acronym','http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=$1',0);
+CALL add_interwiki('advogato','http://www.advogato.org/$1',0);
+CALL add_interwiki('aiwiki','http://www.ifi.unizh.ch/ailab/aiwiki/aiw.cgi?$1',0);
+CALL add_interwiki('alife','http://news.alife.org/wiki/index.php?$1',0);
+CALL add_interwiki('annotation','http://bayle.stanford.edu/crit/nph-med.cgi/$1',0);
+CALL add_interwiki('annotationwiki','http://www.seedwiki.com/page.cfm?wikiid=368&doc=$1',0);
+CALL add_interwiki('arxiv','http://www.arxiv.org/abs/$1',0);
+CALL add_interwiki('aspienetwiki','http://aspie.mela.de/Wiki/index.php?title=$1',0);
+CALL add_interwiki('bemi','http://bemi.free.fr/vikio/index.php?$1',0);
+CALL add_interwiki('benefitswiki','http://www.benefitslink.com/cgi-bin/wiki.cgi?$1',0);
+CALL add_interwiki('brasilwiki','http://rio.ifi.unizh.ch/brasilienwiki/index.php/$1',0);
+CALL add_interwiki('bridgeswiki','http://c2.com/w2/bridges/$1',0);
+CALL add_interwiki('c2find','http://c2.com/cgi/wiki?FindPage&value=$1',0);
+CALL add_interwiki('cache','http://www.google.com/search?q=cache:$1',0);
+CALL add_interwiki('ciscavate','http://ciscavate.org/index.php/$1',0);
+CALL add_interwiki('cliki','http://ww.telent.net/cliki/$1',0);
+CALL add_interwiki('cmwiki','http://www.ourpla.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('codersbase','http://www.codersbase.com/$1',0);
+CALL add_interwiki('commons','http://commons.wikimedia.org/wiki/$1',0);
+CALL add_interwiki('consciousness','http://teadvus.inspiral.org/',0);
+CALL add_interwiki('corpknowpedia','http://corpknowpedia.org/wiki/index.php/$1',0);
+CALL add_interwiki('creationmatters','http://www.ourpla.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('dejanews','http://www.deja.com/=dnc/getdoc.xp?AN=$1',0);
+CALL add_interwiki('demokraatia','http://wiki.demokraatia.ee/',0);
+CALL add_interwiki('dictionary','http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1',0);
+CALL add_interwiki('disinfopedia','http://www.disinfopedia.org/wiki.phtml?title=$1',0);
+CALL add_interwiki('diveintoosx','http://diveintoosx.org/$1',0);
+CALL add_interwiki('docbook','http://docbook.org/wiki/moin.cgi/$1',0);
+CALL add_interwiki('dolphinwiki','http://www.object-arts.com/wiki/html/Dolphin/$1',0);
+CALL add_interwiki('drumcorpswiki','http://www.drumcorpswiki.com/index.php/$1',0);
+CALL add_interwiki('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0);
+CALL add_interwiki('eĉei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('echei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('ecxei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('efnetceewiki','http://purl.net/wiki/c/$1',0);
+CALL add_interwiki('efnetcppwiki','http://purl.net/wiki/cpp/$1',0);
+CALL add_interwiki('efnetpythonwiki','http://purl.net/wiki/python/$1',0);
+CALL add_interwiki('efnetxmlwiki','http://purl.net/wiki/xml/$1',0);
+CALL add_interwiki('eljwiki','http://elj.sourceforge.net/phpwiki/index.php/$1',0);
+CALL add_interwiki('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('elibre','http://enciclopedia.us.es/index.php/$1',0);
+CALL add_interwiki('eokulturcentro','http://esperanto.toulouse.free.fr/wakka.php?wiki=$1',0);
+CALL add_interwiki('evowiki','http://www.evowiki.org/index.php/$1',0);
+CALL add_interwiki('finalempire','http://final-empire.sourceforge.net/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('firstwiki','http://firstwiki.org/index.php/$1',0);
+CALL add_interwiki('foldoc','http://www.foldoc.org/foldoc/foldoc.cgi?$1',0);
+CALL add_interwiki('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0);
+CALL add_interwiki('fr.be','http://fr.wikinations.be/$1',0);
+CALL add_interwiki('fr.ca','http://fr.ca.wikinations.org/$1',0);
+CALL add_interwiki('fr.fr','http://fr.fr.wikinations.org/$1',0);
+CALL add_interwiki('fr.org','http://fr.wikinations.org/$1',0);
+CALL add_interwiki('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0);
+CALL add_interwiki('gamewiki','http://gamewiki.org/wiki/index.php/$1',0);
+CALL add_interwiki('gej','http://www.esperanto.de/cgi-bin/aktivikio/wiki.pl?$1',0);
+CALL add_interwiki('gentoo-wiki','http://gentoo-wiki.com/$1',0);
+CALL add_interwiki('globalvoices','http://cyber.law.harvard.edu/dyn/globalvoices/wiki/$1',0);
+CALL add_interwiki('gmailwiki','http://www.gmailwiki.com/index.php/$1',0);
+CALL add_interwiki('google','http://www.google.com/search?q=$1',0);
+CALL add_interwiki('googlegroups','http://groups.google.com/groups?q=$1',0);
+CALL add_interwiki('gotamac','http://www.got-a-mac.org/$1',0);
+CALL add_interwiki('greencheese','http://www.greencheese.org/$1',0);
+CALL add_interwiki('hammondwiki','http://www.dairiki.org/HammondWiki/index.php3?$1',0);
+CALL add_interwiki('haribeau','http://wiki.haribeau.de/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('hewikisource','http://he.wikisource.org/wiki/$1',1);
+CALL add_interwiki('herzkinderwiki','http://www.herzkinderinfo.de/Mediawiki/index.php/$1',0);
+CALL add_interwiki('hrwiki','http://www.hrwiki.org/index.php/$1',0);
+CALL add_interwiki('iawiki','http://www.IAwiki.net/$1',0);
+CALL add_interwiki('imdb','http://us.imdb.com/Title?$1',0);
+CALL add_interwiki('infosecpedia','http://www.infosecpedia.org/pedia/index.php/$1',0);
+CALL add_interwiki('jargonfile','http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1',0);
+CALL add_interwiki('jefo','http://www.esperanto-jeunes.org/vikio/index.php?$1',0);
+CALL add_interwiki('jiniwiki','http://www.cdegroot.com/cgi-bin/jini?$1',0);
+CALL add_interwiki('jspwiki','http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=$1',0);
+CALL add_interwiki('kerimwiki','http://wiki.oxus.net/$1',0);
+CALL add_interwiki('kmwiki','http://www.voght.com/cgi-bin/pywiki?$1',0);
+CALL add_interwiki('knowhow','http://www2.iro.umontreal.ca/~paquetse/cgi-bin/wiki.cgi?$1',0);
+CALL add_interwiki('lanifexwiki','http://opt.lanifex.com/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('lasvegaswiki','http://wiki.gmnow.com/index.php/$1',0);
+CALL add_interwiki('linuxwiki','http://www.linuxwiki.de/$1',0);
+CALL add_interwiki('lojban','http://www.lojban.org/tiki/tiki-index.php?page=$1',0);
+CALL add_interwiki('lqwiki','http://wiki.linuxquestions.org/wiki/$1',0);
+CALL add_interwiki('lugkr','http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1',0);
+CALL add_interwiki('lutherwiki','http://www.lutheranarchives.com/mw/index.php/$1',0);
+CALL add_interwiki('mathsongswiki','http://SeedWiki.com/page.cfm?wikiid=237&doc=$1',0);
+CALL add_interwiki('mbtest','http://www.usemod.com/cgi-bin/mbtest.pl?$1',0);
+CALL add_interwiki('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0);
+CALL add_interwiki('mediazilla','http://bugzilla.wikipedia.org/$1',1);
+CALL add_interwiki('memoryalpha','http://www.memory-alpha.org/en/index.php/$1',0);
+CALL add_interwiki('metaweb','http://www.metaweb.com/wiki/wiki.phtml?title=$1',0);
+CALL add_interwiki('metawiki','http://sunir.org/apps/meta.pl?$1',0);
+CALL add_interwiki('metawikipedia','http://meta.wikimedia.org/wiki/$1',0);
+CALL add_interwiki('moinmoin','http://purl.net/wiki/moin/$1',0);
+CALL add_interwiki('mozillawiki','http://wiki.mozilla.org/index.php/$1',0);
+CALL add_interwiki('muweb','http://www.dunstable.com/scripts/MuWebWeb?$1',0);
+CALL add_interwiki('netvillage','http://www.netbros.com/?$1',0);
+CALL add_interwiki('oeis','http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=$1',0);
+CALL add_interwiki('openfacts','http://openfacts.berlios.de/index.phtml?title=$1',0);
+CALL add_interwiki('openwiki','http://openwiki.com/?$1',0);
+CALL add_interwiki('opera7wiki','http://nontroppo.org/wiki/$1',0);
+CALL add_interwiki('orgpatterns','http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?$1',0);
+CALL add_interwiki('osi reference model','http://wiki.tigma.ee/',0);
+CALL add_interwiki('pangalacticorg','http://www.pangalactic.org/Wiki/$1',0);
+CALL add_interwiki('personaltelco','http://www.personaltelco.net/index.cgi/$1',0);
+CALL add_interwiki('patwiki','http://gauss.ffii.org/$1',0);
+CALL add_interwiki('phpwiki','http://phpwiki.sourceforge.net/phpwiki/index.php?$1',0);
+CALL add_interwiki('pikie','http://pikie.darktech.org/cgi/pikie?$1',0);
+CALL add_interwiki('pmeg','http://www.bertilow.com/pmeg/$1.php',0);
+CALL add_interwiki('ppr','http://c2.com/cgi/wiki?$1',0);
+CALL add_interwiki('purlnet','http://purl.oclc.org/NET/$1',0);
+CALL add_interwiki('pythoninfo','http://www.python.org/cgi-bin/moinmoin/$1',0);
+CALL add_interwiki('pythonwiki','http://www.pythonwiki.de/$1',0);
+CALL add_interwiki('pywiki','http://www.voght.com/cgi-bin/pywiki?$1',0);
+CALL add_interwiki('raec','http://www.raec.clacso.edu.ar:8080/raec/Members/raecpedia/$1',0);
+CALL add_interwiki('revo','http://purl.org/NET/voko/revo/art/$1.html',0);
+CALL add_interwiki('rfc','http://www.rfc-editor.org/rfc/rfc$1.txt',0);
+CALL add_interwiki('s23wiki','http://is-root.de/wiki/index.php/$1',0);
+CALL add_interwiki('scoutpedia','http://www.scoutpedia.info/index.php/$1',0);
+CALL add_interwiki('seapig','http://www.seapig.org/$1',0);
+CALL add_interwiki('seattlewiki','http://seattlewiki.org/wiki/$1',0);
+CALL add_interwiki('seattlewireless','http://seattlewireless.net/?$1',0);
+CALL add_interwiki('seeds','http://www.IslandSeeds.org/wiki/$1',0);
+CALL add_interwiki('senseislibrary','http://senseis.xmp.net/?$1',0);
+CALL add_interwiki('shakti','http://cgi.algonet.se/htbin/cgiwrap/pgd/ShaktiWiki/$1',0);
+CALL add_interwiki('slashdot','http://slashdot.org/article.pl?sid=$1',0);
+CALL add_interwiki('smikipedia','http://www.smikipedia.org/$1',0);
+CALL add_interwiki('sockwiki','http://wiki.socklabs.com/$1',0);
+CALL add_interwiki('sourceforge','http://sourceforge.net/$1',0);
+CALL add_interwiki('squeak','http://minnow.cc.gatech.edu/squeak/$1',0);
+CALL add_interwiki('strikiwiki','http://ch.twi.tudelft.nl/~mostert/striki/teststriki.pl?$1',0);
+CALL add_interwiki('susning','http://www.susning.nu/$1',0);
+CALL add_interwiki('svgwiki','http://www.protocol7.com/svg-wiki/default.asp?$1',0);
+CALL add_interwiki('tavi','http://tavi.sourceforge.net/$1',0);
+CALL add_interwiki('tejo','http://www.tejo.org/vikio/$1',0);
+CALL add_interwiki('terrorwiki','http://www.liberalsagainstterrorism.com/wiki/index.php/$1',0);
+CALL add_interwiki('tmbw','http://www.tmbw.net/wiki/index.php/$1',0);
+CALL add_interwiki('tmnet','http://www.technomanifestos.net/?$1',0);
+CALL add_interwiki('tmwiki','http://www.EasyTopicMaps.com/?page=$1',0);
+CALL add_interwiki('turismo','http://www.tejo.org/turismo/$1',0);
+CALL add_interwiki('theopedia','http://www.theopedia.com/$1',0);
+CALL add_interwiki('twiki','http://twiki.org/cgi-bin/view/$1',0);
+CALL add_interwiki('twistedwiki','http://purl.net/wiki/twisted/$1',0);
+CALL add_interwiki('uea','http://www.tejo.org/uea/$1',0);
+CALL add_interwiki('unreal','http://wiki.beyondunreal.com/wiki/$1',0);
+CALL add_interwiki('ursine','http://ursine.ca/$1',0);
+CALL add_interwiki('usej','http://www.tejo.org/usej/$1',0);
+CALL add_interwiki('usemod','http://www.usemod.com/cgi-bin/wiki.pl?$1',0);
+CALL add_interwiki('visualworks','http://wiki.cs.uiuc.edu/VisualWorks/$1',0);
+CALL add_interwiki('warpedview','http://www.warpedview.com/index.php/$1',0);
+CALL add_interwiki('webdevwikinl','http://www.promo-it.nl/WebDevWiki/index.php?page=$1',0);
+CALL add_interwiki('webisodes','http://www.webisodes.org/$1',0);
+CALL add_interwiki('webseitzwiki','http://webseitz.fluxent.com/wiki/$1',0);
+CALL add_interwiki('why','http://clublet.com/c/c/why?$1',0);
+CALL add_interwiki('wiki','http://c2.com/cgi/wiki?$1',0);
+CALL add_interwiki('wikia','http://www.wikia.com/wiki/index.php/$1',0);
+CALL add_interwiki('wikibooks','http://en.wikibooks.org/wiki/$1',1);
+CALL add_interwiki('wikicities','http://www.wikicities.com/index.php/$1',0);
+CALL add_interwiki('wikif1','http://www.wikif1.org/$1',0);
+CALL add_interwiki('wikinfo','http://www.wikinfo.org/wiki.php?title=$1',0);
+CALL add_interwiki('wikimedia','http://wikimediafoundation.org/wiki/$1',0);
+CALL add_interwiki('wikiquote','http://en.wikiquote.org/wiki/$1',1);
+CALL add_interwiki('wikinews','http://en.wikinews.org/wiki/$1',0);
+CALL add_interwiki('wikisource','http://sources.wikipedia.org/wiki/$1',1);
+CALL add_interwiki('wikispecies','http://species.wikipedia.org/wiki/$1',1);
+CALL add_interwiki('wikitravel','http://wikitravel.org/en/$1',0);
+CALL add_interwiki('wikiworld','http://WikiWorld.com/wiki/index.php/$1',0);
+CALL add_interwiki('wiktionary','http://en.wiktionary.org/wiki/$1',1);
+CALL add_interwiki('wlug','http://www.wlug.org.nz/$1',0);
+CALL add_interwiki('wlwiki','http://winslowslair.supremepixels.net/wiki/index.php/$1',0);
+CALL add_interwiki('ypsieyeball','http://sknkwrks.dyndns.org:1957/writewiki/wiki.pl?$1',0);
+CALL add_interwiki('zwiki','http://www.zwiki.org/$1',0);
+CALL add_interwiki('zzz wiki','http://wiki.zzz.ee/',0);
+CALL add_interwiki('wikt','http://en.wiktionary.org/wiki/$1',1);
+
--- /dev/null
+-- 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.
+
+CREATE SEQUENCE user_user_id_seq;
+
+CREATE TABLE "user" (
+ user_id NUMBER(5) NOT NULL PRIMARY KEY,
+ user_name VARCHAR2(255) DEFAULT '' NOT NULL,
+ user_real_name VARCHAR2(255) DEFAULT '',
+ user_password VARCHAR2(128) DEFAULT '',
+ user_newpassword VARCHAR2(128) default '',
+ user_email VARCHAR2(255) default '',
+ user_options CLOB default '',
+ user_touched TIMESTAMP WITH TIME ZONE,
+ user_token CHAR(32) default '',
+ user_email_authenticated TIMESTAMP WITH TIME ZONE DEFAULT NULL,
+ user_email_token CHAR(32),
+ user_email_token_expires TIMESTAMP WITH TIME ZONE DEFAULT NULL
+);
+CREATE UNIQUE INDEX user_name_idx ON "user" (user_name);
+CREATE INDEX user_email_token_idx ON "user" (user_email_token);
+
+CREATE TABLE user_groups (
+ ug_user NUMBER(5) DEFAULT '0' NOT NULL
+ REFERENCES "user" (user_id)
+ ON DELETE CASCADE,
+ ug_group VARCHAR2(16) NOT NULL,
+ CONSTRAINT user_groups_pk PRIMARY KEY (ug_user, ug_group)
+);
+CREATE INDEX user_groups_group_idx ON user_groups(ug_group);
+
+CREATE TABLE user_newtalk (
+ user_id NUMBER(5) DEFAULT 0 NOT NULL,
+ user_ip VARCHAR2(40) DEFAULT '' NOT NULL
+);
+CREATE INDEX user_newtalk_id_idx ON user_newtalk(user_id);
+CREATE INDEX user_newtalk_ip_idx ON user_newtalk(user_ip);
+
+CREATE SEQUENCE page_page_id_seq;
+CREATE TABLE page (
+ page_id NUMBER(8) NOT NULL PRIMARY KEY,
+ page_namespace NUMBER(5) NOT NULL,
+ page_title VARCHAR(255) NOT NULL,
+ page_restrictions CLOB DEFAULT '',
+ page_counter NUMBER(20) DEFAULT 0 NOT NULL,
+ page_is_redirect NUMBER(1) DEFAULT 0 NOT NULL,
+ page_is_new NUMBER(1) DEFAULT 0 NOT NULL,
+ page_random NUMBER(25, 24) NOT NULL,
+ page_touched TIMESTAMP WITH TIME ZONE,
+ page_latest NUMBER(8) NOT NULL,
+ page_len NUMBER(8) DEFAULT 0
+);
+CREATE UNIQUE INDEX page_id_namespace_title_idx 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 SEQUENCE rev_rev_id_val;
+CREATE TABLE revision (
+ rev_id NUMBER(8) NOT NULL,
+ rev_page NUMBER(8) NOT NULL
+ REFERENCES page (page_id)
+ ON DELETE CASCADE,
+ rev_text_id NUMBER(8) NOT NULL,
+ rev_comment CLOB,
+ rev_user NUMBER(8) DEFAULT 0 NOT NULL,
+ rev_user_text VARCHAR2(255) DEFAULT '' NOT NULL,
+ rev_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
+ rev_minor_edit NUMBER(1) DEFAULT 0 NOT NULL,
+ rev_deleted NUMBER(1) DEFAULT 0 NOT NULL,
+ CONSTRAINT revision_pk PRIMARY KEY (rev_page, rev_id)
+);
+
+CREATE UNIQUE INDEX rev_id_idx ON revision(rev_id);
+CREATE INDEX rev_timestamp_idx ON revision(rev_timestamp);
+CREATE INDEX rev_page_timestamp_idx ON revision(rev_page, rev_timestamp);
+CREATE INDEX rev_user_timestamp_idx ON revision(rev_user, rev_timestamp);
+CREATE INDEX rev_usertext_timestamp_idx ON revision(rev_user_text, rev_timestamp);
+
+CREATE SEQUENCE text_old_id_val;
+
+CREATE TABLE text (
+ old_id NUMBER(8) NOT NULL,
+ old_text CLOB,
+ old_flags CLOB,
+ CONSTRAINT text_pk PRIMARY KEY (old_id)
+);
+
+CREATE TABLE archive (
+ ar_namespace NUMBER(5) NOT NULL,
+ ar_title VARCHAR2(255) NOT NULL,
+ ar_text CLOB,
+ ar_comment CLOB,
+ ar_user NUMBER(8),
+ ar_user_text VARCHAR2(255) NOT NULL,
+ ar_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
+ ar_minor_edit NUMBER(1) DEFAULT 0 NOT NULL,
+ ar_flags CLOB,
+ ar_rev_id NUMBER(8),
+ ar_text_id NUMBER(8)
+);
+CREATE INDEX archive_name_title_timestamp ON archive(ar_namespace,ar_title,ar_timestamp);
+
+CREATE TABLE pagelinks (
+ pl_from NUMBER(8) NOT NULL
+ REFERENCES page(page_id)
+ ON DELETE CASCADE,
+ pl_namespace NUMBER(4) DEFAULT 0 NOT NULL,
+ pl_title VARCHAR2(255) NOT NULL
+);
+CREATE UNIQUE INDEX pl_from ON pagelinks(pl_from, pl_namespace, pl_title);
+CREATE INDEX pl_namespace ON pagelinks(pl_namespace, pl_title);
+
+CREATE TABLE imagelinks (
+ il_from NUMBER(8) NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
+ il_to VARCHAR2(255) NOT NULL
+);
+CREATE UNIQUE INDEX il_from ON imagelinks(il_from, il_to);
+CREATE INDEX il_to ON imagelinks(il_to);
+
+CREATE TABLE categorylinks (
+ cl_from NUMBER(8) NOT NULL REFERENCES page(page_id) ON DELETE CASCADE,
+ cl_to VARCHAR2(255) NOT NULL,
+ cl_sortkey VARCHAR2(86) default '',
+ 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 INDEX cl_timestamp ON categorylinks(cl_to, cl_timestamp);
+
+--
+-- Contains a single row with some aggregate info
+-- on the state of the site.
+--
+CREATE TABLE site_stats (
+ ss_row_id NUMBER(8) NOT NULL,
+ ss_total_views NUMBER(20) default 0,
+ ss_total_edits NUMBER(20) default 0,
+ ss_good_articles NUMBER(20) default 0,
+ ss_total_pages NUMBER(20) default -1,
+ ss_users NUMBER(20) default -1,
+ ss_admins NUMBER(10) default -1
+);
+CREATE UNIQUE INDEX ss_row_id ON site_stats(ss_row_id);
+
+--
+-- Stores an ID for every time any article is visited;
+-- depending on $wgHitcounterUpdateFreq, it is
+-- periodically cleared and the page_counter column
+-- in the page table updated for the all articles
+-- that have been visited.)
+--
+CREATE TABLE hitcounter (
+ hc_id NUMBER NOT NULL
+);
+
+--
+-- The internet is full of jerks, alas. Sometimes it's handy
+-- to block a vandal or troll account.
+--
+CREATE SEQUENCE ipblocks_ipb_id_val;
+CREATE TABLE ipblocks (
+ ipb_id NUMBER(8) NOT NULL,
+ ipb_address VARCHAR2(40),
+ ipb_user NUMBER(8),
+ ipb_by NUMBER(8) NOT NULL
+ REFERENCES "user" (user_id)
+ ON DELETE CASCADE,
+ ipb_reason CLOB,
+ ipb_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
+ ipb_auto NUMBER(1) DEFAULT 0 NOT NULL,
+ ipb_expiry TIMESTAMP WITH TIME ZONE,
+ CONSTRAINT ipblocks_pk PRIMARY KEY (ipb_id)
+);
+CREATE INDEX ipb_address ON ipblocks(ipb_address);
+CREATE INDEX ipb_user ON ipblocks(ipb_user);
+
+CREATE TABLE image (
+ img_name VARCHAR2(255) NOT NULL,
+ img_size NUMBER(8) NOT NULL,
+ img_width NUMBER(5) NOT NULL,
+ img_height NUMBER(5) NOT NULL,
+ img_metadata CLOB,
+ img_bits NUMBER(3),
+ img_media_type VARCHAR2(10),
+ img_major_mime VARCHAR2(12) DEFAULT 'unknown',
+ img_minor_mime VARCHAR2(32) DEFAULT 'unknown',
+ img_description CLOB NOT NULL,
+ img_user NUMBER(8) NOT NULL REFERENCES "user"(user_id) ON DELETE CASCADE,
+ img_user_text VARCHAR2(255) NOT NULL,
+ img_timestamp TIMESTAMP WITH TIME ZONE,
+ CONSTRAINT image_pk PRIMARY KEY (img_name)
+);
+CREATE INDEX img_size_idx ON image(img_size);
+CREATE INDEX img_timestamp_idx ON image(img_timestamp);
+
+CREATE TABLE oldimage (
+ oi_name VARCHAR2(255) NOT NULL,
+ oi_archive_name VARCHAR2(255) NOT NULL,
+ oi_size NUMBER(8) NOT NULL,
+ oi_width NUMBER(5) NOT NULL,
+ oi_height NUMBER(5) NOT NULL,
+ oi_bits NUMBER(3) NOT NULL,
+ oi_description CLOB,
+ oi_user NUMBER(8) NOT NULL REFERENCES "user"(user_id),
+ oi_user_text VARCHAR2(255) NOT NULL,
+ oi_timestamp TIMESTAMP WITH TIME ZONE NOT NULL
+);
+CREATE INDEX oi_name ON oldimage (oi_name);
+
+CREATE SEQUENCE rc_rc_id_seq;
+CREATE TABLE recentchanges (
+ rc_id NUMBER(8) NOT NULL,
+ rc_timestamp TIMESTAMP WITH TIME ZONE,
+ rc_cur_time TIMESTAMP WITH TIME ZONE,
+ rc_user NUMBER(8) DEFAULT 0 NOT NULL,
+ rc_user_text VARCHAR2(255),
+ rc_namespace NUMBER(4) DEFAULT 0 NOT NULL,
+ rc_title VARCHAR2(255) NOT NULL,
+ rc_comment VARCHAR2(255),
+ rc_minor NUMBER(3) DEFAULT 0 NOT NULL,
+ rc_bot NUMBER(3) DEFAULT 0 NOT NULL,
+ rc_new NUMBER(3) DEFAULT 0 NOT NULL,
+ rc_cur_id NUMBER(8),
+ rc_this_oldid NUMBER(8) NOT NULL,
+ rc_last_oldid NUMBER(8) NOT NULL,
+ rc_type NUMBER(3) DEFAULT 0 NOT NULL,
+ rc_moved_to_ns NUMBER(3),
+ rc_moved_to_title VARCHAR2(255),
+ rc_patrolled NUMBER(3) DEFAULT 0 NOT NULL,
+ rc_ip VARCHAR2(40),
+ CONSTRAINT rc_pk PRIMARY KEY (rc_id)
+);
+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 NUMBER(8) NOT NULL
+ REFERENCES "user"(user_id)
+ ON DELETE CASCADE,
+ wl_namespace NUMBER(8) DEFAULT 0 NOT NULL,
+ wl_title VARCHAR2(255) NOT NULL,
+ wl_notificationtimestamp TIMESTAMP WITH TIME ZONE DEFAULT NULL
+);
+CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist
+ (wl_user, wl_namespace, wl_title);
+CREATE INDEX wl_namespace_title ON watchlist(wl_namespace, wl_title);
+
+--
+-- Used by texvc math-rendering extension to keep track
+-- of previously-rendered items.
+--
+CREATE TABLE math (
+ math_inputhash VARCHAR2(16) NOT NULL UNIQUE,
+ math_outputhash VARCHAR2(16) NOT NULL,
+ math_html_conservativeness NUMBER(1) NOT NULL,
+ math_html CLOB,
+ math_mathml CLOB
+);
+
+--
+-- Recognized interwiki link prefixes
+--
+CREATE TABLE interwiki (
+ iw_prefix VARCHAR2(32) NOT NULL UNIQUE,
+ iw_url VARCHAR2(127) NOT NULL,
+ iw_local NUMBER(1) NOT NULL,
+ iw_trans NUMBER(1) DEFAULT 0 NOT NULL
+);
+
+CREATE TABLE querycache (
+ qc_type VARCHAR2(32) NOT NULL,
+ qc_value NUMBER(5) DEFAULT 0 NOT NULL,
+ qc_namespace NUMBER(4) DEFAULT 0 NOT NULL,
+ qc_title VARCHAR2(255)
+);
+CREATE INDEX querycache_type_value ON querycache(qc_type, qc_value);
+
+--
+-- For a few generic cache operations if not using Memcached
+--
+CREATE TABLE objectcache (
+ keyname CHAR(255) DEFAULT '',
+ value CLOB,
+ exptime TIMESTAMP WITH TIME ZONE
+);
+CREATE UNIQUE INDEX oc_keyname_idx ON objectcache(keyname);
+CREATE INDEX oc_exptime_idx ON objectcache(exptime);
+
+CREATE TABLE "validate" (
+ val_user NUMBER(11) DEFAULT 0 NOT NULL,
+ val_page NUMBER(11) DEFAULT 0 NOT NULL,
+ val_revision NUMBER(11) DEFAULT 0 NOT NULL,
+ val_type NUMBER(11) DEFAULT 0 NOT NULL,
+ val_value NUMBER(11) DEFAULT 0,
+ val_comment VARCHAR2(255),
+ val_ip VARCHAR2(20)
+);
+CREATE INDEX val_user ON "validate" (val_user,val_revision);
+
+CREATE TABLE logging (
+ log_type VARCHAR2(10) NOT NULL,
+ log_action VARCHAR2(10) NOT NULL,
+ log_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
+ log_user NUMBER(8) REFERENCES "user"(user_id),
+ log_namespace NUMBER(4),
+ log_title VARCHAR2(255) NOT NULL,
+ log_comment VARCHAR2(255),
+ log_params CLOB
+);
+CREATE INDEX logging_type_name ON logging(log_type, log_timestamp);
+CREATE INDEX logging_user_time ON logging(log_user, log_timestamp);
+CREATE INDEX logging_page_time ON logging(log_namespace, log_title, log_timestamp);
+
+-- Hold group name and description
+--CREATE TABLE /*$wgDBprefix*/groups (
+-- gr_id int(5) unsigned NOT NULL auto_increment,
+-- gr_name varchar(50) NOT NULL default '',
+-- gr_description varchar(255) NOT NULL default '',
+-- gr_rights tinyblob,
+-- PRIMARY KEY (gr_id)
+--
+--) TYPE=InnoDB;
+
+CREATE OR REPLACE PROCEDURE add_user_right (name VARCHAR2, new_right VARCHAR2) AS
+ user_id "user".user_id%TYPE;;
+ user_is_missing EXCEPTION;;
+BEGIN
+ SELECT user_id INTO user_id FROM "user" WHERE user_name = name;;
+ INSERT INTO user_groups (ug_user, ug_group) VALUES(user_id, new_right);;
+EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ DBMS_OUTPUT.PUT_LINE('The specified user does not exist.');;
+END add_user_right;;
+;
+
+CREATE OR REPLACE PROCEDURE add_interwiki (prefix VARCHAR2, url VARCHAR2, is_local NUMBER) AS
+BEGIN
+ INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES(prefix, url, is_local);;
+END add_interwiki;;
+;
\ No newline at end of file
* @todo document
* @package MediaWiki
* @subpackage Maintenance
- */
+ */
/** */
$options = array( 'quick' );
require_once( "commandLine.inc" );
require_once( "updaters.inc" );
$wgTitle = Title::newFromText( "MediaWiki database updater" );
-$wgDatabase = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
+$dbclass = 'Database'.ucfirst($wgDBtype);
+require_once("$dbclass.php");
+$dbc = new $dbclass;
+$wgDatabase = $dbc->newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname );
print "Going to run database updates for $wgDBname\n";
print "Depending on the size of your database this may take a while!\n";
if( !isset( $options['quick'] ) ) {
print "Abort with control-c in the next five seconds... ";
-
+
for ($i = 5; $i >= 0; --$i) {
echo $i;
sleep(1);
* @package MediaWiki
* @subpackage Maintenance
*/
-
+
/** */
require_once 'convertLinks.inc';
echo "...can't move table $from to $to, $to already exists.\n";
} else {
echo "Moving table $from to $to...";
- dbsource( "maintenance/archives/$patch", $wgDatabase );
+ dbsource( archive($patch), $wgDatabase );
echo "ok\n";
}
} else {
echo "...$name table already exists.\n";
} else {
echo "Creating $name table...";
- dbsource( "maintenance/archives/$patch", $wgDatabase );
+ dbsource( archive($patch), $wgDatabase );
echo "ok\n";
}
}
echo "...have $field field in $table table.\n";
} else {
echo "Adding $field field to table $table...";
- dbsource( "maintenance/archives/$patch" , $wgDatabase );
+ dbsource( archive($patch) , $wgDatabase );
echo "ok\n";
}
}
function update_passwords() {
wfDebugDieBacktrace( "This function needs to be updated or removed.\n" );
-
+
global $wgDatabase;
$fname = "Update script: update_passwords()";
print "\nIt appears that you need to update the user passwords in your\n" .
return true;
}
echo "Creating interwiki table: ";
- dbsource( "maintenance/archives/patch-interwiki.sql" );
+ dbsource( archive("patch-interwiki.sql") );
echo "ok\n";
echo "Adding default interwiki definitions: ";
dbsource( "maintenance/interwiki.sql" );
$meta = $wgDatabase->fieldInfo( "recentchanges", "rc_timestamp" );
if( $meta->multiple_key == 0 ) {
echo "Updating indexes to 20031107: ";
- dbsource( "maintenance/archives/patch-indexes.sql" );
+ dbsource( archive("patch-indexes.sql") );
echo "ok\n";
return true;
}
echo "...image primary key already set.\n";
} else {
echo "Making img_name the primary key... ";
- dbsource( "maintenance/archives/patch-image_name_primary.sql", $wgDatabase );
+ dbsource( archive("patch-image_name_primary.sql"), $wgDatabase );
echo "ok\n";
}
}
* which causes a collation mismatch error on joins in MySQL 4.1.
*/
function do_logging_encoding() {
- global $wgDatabase;
+ global $wgDatabase, $wgDBtype;
+ if ($wgDBtype != 'mysql')
+ return;
$logging = $wgDatabase->tableName( 'logging' );
$res = $wgDatabase->query( "SELECT log_title FROM $logging LIMIT 0" );
$flags = explode( ' ', mysql_field_flags( $res, 0 ) );
$wgDatabase->freeResult( $res );
-
+
if( in_array( 'binary', $flags ) ) {
echo "Logging table has correct title encoding.\n";
} else {
echo "...converting from cur/old to page/revision/text DB structure.\n"; flush();
echo wfTimestamp();
echo "......checking for duplicate entries.\n"; flush();
-
+
extract( $wgDatabase->tableNames( 'cur', 'old', 'page', 'revision', 'text' ) );
$rows = $wgDatabase->query( "SELECT cur_title, cur_namespace, COUNT(cur_namespace) AS c
echo ( sprintf( " %-60s %3s %5s\n", $row->cur_title, $row->cur_namespace, $row->c ) );
}
$sql = "SELECT cur_title, cur_namespace, cur_id, cur_timestamp FROM $cur WHERE ";
- $firstCond = true;
+ $firstCond = true;
foreach ( $duplicate as $ns => $titles ) {
if ( $firstCond ) {
$firstCond = false;
echo wfTimestamp();
echo "......<b>Deleted</b> ".$wgDatabase->affectedRows()." records.\n";
}
-
+
echo wfTimestamp();
echo "......Creating tables.\n";
rev_timestamp char(14) binary NOT NULL default '',
rev_minor_edit tinyint(1) unsigned NOT NULL default '0',
rev_deleted tinyint(1) unsigned NOT NULL default '0',
-
+
PRIMARY KEY rev_page_id (rev_page, rev_id),
UNIQUE INDEX rev_id (rev_id),
INDEX rev_timestamp (rev_timestamp),
echo wfTimestamp();
echo "......Renaming old.\n";
$wgDatabase->query( "ALTER TABLE $old RENAME TO $text", $fname );
-
+
echo wfTimestamp();
echo "...done.\n";
}
}
function do_namespace_size_on( $table, $prefix ) {
- global $wgDatabase;
+ global $wgDatabase, $wgDBtype;
+ if ($wgDBtype != 'mysql')
+ return;
$field = $prefix . '_namespace';
-
+
$tablename = $wgDatabase->tableName( $table );
$result = $wgDatabase->query( "SHOW COLUMNS FROM $tablename LIKE '$field'" );
$info = $wgDatabase->fetchObject( $result );
$wgDatabase->freeResult( $result );
-
+
if( substr( $info->Type, 0, 3 ) == 'int' ) {
echo "...$field is already a full int ($info->Type).\n";
} else {
echo "Promoting $field from $info->Type to int... ";
-
+
$sql = "ALTER TABLE $tablename MODIFY $field int NOT NULL";
$wgDatabase->query( $sql );
-
+
echo "ok\n";
}
}
dbsource( "maintenance/archives/patch-pagelinks.sql", $wgDatabase );
echo "ok\n";
flush();
-
+
global $wgCanonicalNamespaceNames;
foreach( $wgCanonicalNamespaceNames as $ns => $name ) {
if( $ns != 0 ) {
function do_pagelinks_namespace( $namespace ) {
global $wgDatabase, $wgContLang;
-
+
$ns = IntVal( $namespace );
echo "Cleaning up broken links for namespace $ns... ";
-
+
$pagelinks = $wgDatabase->tableName( 'pagelinks' );
$name = $wgContLang->getNsText( $ns );
$prefix = $wgDatabase->strencode( $name );
$likeprefix = str_replace( '_', '\\_', $prefix);
-
+
$sql = "UPDATE $pagelinks
SET pl_namespace=$ns,
pl_title=TRIM(LEADING '$prefix:' FROM pl_title)
WHERE pl_namespace=0
AND pl_title LIKE '$likeprefix:%'";
-
+
$wgDatabase->query( $sql, 'do_pagelinks_namespace' );
echo "ok\n";
}
function do_drop_img_type() {
global $wgDatabase;
-
+
if( $wgDatabase->fieldExists( 'image', 'img_type' ) ) {
echo "Dropping unused img_type field in image table... ";
dbsource( "maintenance/archives/patch-drop_img_type.sql", $wgDatabase );
function do_user_groups_update() {
$fname = 'do_user_groups_update';
global $wgDatabase;
-
+
if( $wgDatabase->tableExists( 'user_groups' ) ) {
echo "...user_groups table already exists.\n";
return do_user_groups_reformat();
}
-
+
echo "Adding user_groups table... ";
dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase );
echo "ok\n";
-
+
if( !$wgDatabase->tableExists( 'user_rights' ) ) {
if( $wgDatabase->fieldExists( 'user', 'user_rights' ) ) {
echo "Upgrading from a 1.3 or older database? Breaking out user_rights for conversion...";
return;
}
}
-
+
echo "Converting user_rights table to user_groups... ";
$result = $wgDatabase->select( 'user_rights',
array( 'ur_user', 'ur_rights' ),
array( "ur_rights != ''" ),
$fname );
-
+
while( $row = $wgDatabase->fetchObject( $result ) ) {
$groups = array_unique(
array_map( 'trim',
explode( ',', $row->ur_rights ) ) );
-
+
foreach( $groups as $group ) {
$wgDatabase->insert( 'user_groups',
array(
# Check for bogus formats from previous 1.5 alpha code.
global $wgDatabase;
$info = $wgDatabase->fieldInfo( 'user_groups', 'ug_group' );
-
+
if( $info->type == 'int' ) {
$oldug = $wgDatabase->tableName( 'user_groups' );
$newug = $wgDatabase->tableName( 'user_groups_bogus' );
echo "user_groups is in bogus intermediate format. Renaming to $newug... ";
$wgDatabase->query( "ALTER TABLE $oldug RENAME TO $newug" );
echo "ok\n";
-
+
echo "Re-adding fresh user_groups table... ";
dbsource( 'maintenance/archives/patch-user_groups.sql', $wgDatabase );
echo "ok\n";
-
+
echo "***\n";
echo "*** WARNING: You will need to manually fix up user permissions in the user_groups\n";
echo "*** table. Old 1.5 alpha versions did some pretty funky stuff...\n";
} else {
echo "...user_groups is in current format.\n";
}
-
+
}
function do_all_updates() {
global $wgNewTables, $wgNewFields, $wgRenamedTables;
-
+
# Rename tables
foreach ( $wgRenamedTables as $tableRecord ) {
rename_table( $tableRecord[0], $tableRecord[1], $tableRecord[2] );
add_field( $fieldRecord[0], $fieldRecord[1], $fieldRecord[2] );
flush();
}
-
+
# Do schema updates which require special handling
do_interwiki_update(); flush();
do_index_update(); flush();
do_user_update(); flush();
###### do_copy_newtalk_to_watchlist(); flush();
do_logging_encoding(); flush();
-
+
do_schema_restructuring(); flush();
do_inverse_timestamp(); flush();
do_text_id(); flush();
do_namespace_size(); flush();
-
+
do_pagelinks_update(); flush();
-
+
do_drop_img_type(); flush();
-
+
do_user_unique_update(); flush();
do_user_groups_update(); flush();
-
+
initialiseMessages(); flush();
}
+function archive($name) {
+ global $wgDBtype;
+ switch ($wgDBtype) {
+ case "oracle":
+ return "maintenance/oracle/archives/$name";
+ default:
+ return "maintenance/archives/$name";
+ }
+}
?>