+# Repository management
.svn
-*~
+
+# Editors
*.kate-swp
+*~
.*.swp
-.classpath
-.idea
-.metadata*
.project
-.settings
-AdminSettings.php
-LocalSettings.php
-StartProfiler.php
cscope.files
cscope.out
-favicon.ico
+## NetBeans
nbproject*
project.index
-static*
-tags
+
+# MediaWiki install & usage
cache/*.cdb
images/[0-9a-f]
images/archive
images/deleted
images/temp
images/thumb
+## Extension:EasyTimeline
images/timeline
images/tmp
-maintenance/dev/data
maintenance/.mweval_history
maintenance/.mwsql_history
+maintenance/dev/data
+AdminSettings.php
+LocalSettings.php
+StartProfiler.php
+
+# Operating systems
+## Mac OS X
+.DS_Store
+
+# Misc
+.classpath
+.idea
+.metadata*
+.settings
+favicon.ico
+static*
+tags
* The user right 'upload_by_url' is no longer given to sysops by default.
This only affects installations which have $wgAllowCopyUploads set to true.
* Removed f-prot support from $wgAntivirusSetup.
-* $wgDBerrorLogInUTC to log error in $wgDBerrorLog using an UTC date instead
- of the wiki timezone set by $wgLocalTimezone.
+* New variable $wgDBerrorLogTZ to provide dates in the error log in a
+ different timezone than the wiki timezone set by $wgLocalTimezone.
=== New features in 1.20 ===
* Added TitleIsAlwaysKnown hook which gets called when determining if a page exists.
* Session storage can now configured independently of general object cache
storage, by using $wgSessionCacheType. $wgSessionsInMemcached has been
renamed to $wgSessionsInObjectCache, with the old name retained for backwards
- compatibility.
+ compatibility. When this feature is enabled, the expiry time can now be
+ configured with $wgObjectCacheSessionExpiry.
* Implemented mw.user.getGroups for getting and caching user groups.
* (bug 37830) Added $wgRequirePasswordforEmailChange to control whether password
confirmation is required for changing an email address or not.
so the WikiPage code wasn't useful there either.
* Deprecated mw.user.name in favour of mw.user.getName.
* Deprecated mw.user.anonymous in favour of mw.user.isAnon.
+* Deprecated DatabaseBase functions newFromParams(), newFromType(), set(),
+ quote_ident(), and escapeLike() were removed.
== Compatibility ==
/** File to log database errors to */
$wgDBerrorLog = false;
+
/**
- * Override wiki timezone to UTC for wgDBerrorLog
+ * Timezone to use in the error log.
+ * Defaults to the wiki timezone ($wgLocalTimezone).
+ *
+ * A list of useable timezones can found at:
+ * http://php.net/manual/en/timezones.php
+ *
+ * @par Examples:
+ * @code
+ * $wgLocaltimezone = 'UTC';
+ * $wgLocaltimezone = 'GMT';
+ * $wgLocaltimezone = 'PST8PDT';
+ * $wgLocaltimezone = 'Europe/Sweden';
+ * $wgLocaltimezone = 'CET';
+ * @endcode
+ *
* @since 1.20
*/
-$wgDBerrorLogInUTC = false;
+$wgDBerrorLogTZ = false;
/** When to give an error message */
$wgDBClusterTimeout = 10;
*/
$wgSessionsInObjectCache = false;
+/**
+ * The expiry time to use for session storage when $wgSessionsInObjectCache is
+ * enabled, in seconds.
+ */
+$wgObjectCacheSessionExpiry = 3600;
+
/**
* This is used for setting php's session.save_handler. In practice, you will
* almost never need to change this ever. Other options might be 'user' or
* Timezones can be translated by editing MediaWiki messages of type
* timezone-nameinlowercase like timezone-utc.
*
+ * A list of useable timezones can found at:
+ * http://php.net/manual/en/timezones.php
+ *
* @par Examples:
* @code
+ * $wgLocaltimezone = 'UTC';
* $wgLocaltimezone = 'GMT';
* $wgLocaltimezone = 'PST8PDT';
* $wgLocaltimezone = 'Europe/Sweden';
* @param $text String: database error message.
*/
function wfLogDBError( $text ) {
- global $wgDBerrorLog, $wgDBerrorLogInUTC;
+ global $wgDBerrorLog, $wgDBerrorLogTZ;
+ static $logDBErrorTimeZoneObject = null;
+
if ( $wgDBerrorLog ) {
$host = wfHostname();
$wiki = wfWikiID();
- if( $wgDBerrorLogInUTC ) {
- $wikiTimezone = date_default_timezone_get();
- date_default_timezone_set( 'UTC' );
- }
- $date = date( 'D M j G:i:s T Y' );
- if( $wgDBerrorLogInUTC ) {
- // Restore timezone
- date_default_timezone_set( $wikiTimezone );
+ if ( $wgDBerrorLogTZ && !$logDBErrorTimeZoneObject ) {
+ $logDBErrorTimeZoneObject = new DateTimeZone( $wgDBerrorLogTZ );
}
+ $d = date_create( "now", $logDBErrorTimeZoneObject );
+
+ $date = $d->format( 'D M j G:i:s T Y' );
+
$text = "$date\t$host\t$wiki\t$text";
wfErrorLog( $text, $wgDBerrorLog );
}
/**
* Return a Vary: header on which to vary caches. Based on the keys of $mVaryHeader,
* such as Accept-Encoding or Cookie
- *
+ *
* @return String
*/
public function getVaryHeader() {
* Add a "return to" link pointing to a specified title
*
* @param $title Title to link
- * @param $query String query string
+ * @param $query Array query string parameters
* @param $text String text of the link (input is not escaped)
*/
public function addReturnTo( $title, $query = array(), $text = null ) {
$titleObj = Title::newMainPage();
}
- $this->addReturnTo( $titleObj, $returntoquery );
+ $this->addReturnTo( $titleObj, wfCgiToArray( $returntoquery ) );
}
/**
if ( wfRunHooks( 'AbortEmailNotification', array($editor, $title) ) ) {
# @todo FIXME: This would be better as an extension hook
$enotif = new EmailNotification();
- $status = $enotif->notifyOnPageChange( $editor, $title,
+ $enotif->notifyOnPageChange( $editor, $title,
$this->mAttribs['rc_timestamp'],
$this->mAttribs['rc_comment'],
$this->mAttribs['rc_minor'],
protected $mTitle;
protected $mCurrent;
+ // Revision deletion constants
const DELETED_TEXT = 1;
const DELETED_COMMENT = 2;
const DELETED_USER = 4;
const DELETED_RESTRICTED = 8;
- // Convenience field
- const SUPPRESSED_USER = 12;
+ const SUPPRESSED_USER = 12; // convenience
+
// Audience options for accessors
const FOR_PUBLIC = 1;
const FOR_THIS_USER = 2;
* Returns null if no such revision can be found.
*
* $flags include:
- * IDBAccessObject::LATEST_READ : Select the data from the master
- * IDBAccessObject::LOCKING_READ : Select & lock the data from the master
- * IDBAccessObject::AVOID_MASTER : Avoid master queries; data may be stale
+ * Revision::READ_LATEST : Select the data from the master
+ * Revision::READ_LOCKING : Select & lock the data from the master
*
* @param $id Integer
* @param $flags Integer (optional)
* to that title, will return null.
*
* $flags include:
- * IDBAccessObject::LATEST_READ : Select the data from the master
- * IDBAccessObject::LOCKING_READ : Select & lock the data from the master
- * IDBAccessObject::AVOID_MASTER : Avoid master queries; data may be stale
+ * Revision::READ_LATEST : Select the data from the master
+ * Revision::READ_LOCKING : Select & lock the data from the master
*
* @param $title Title
* @param $id Integer (optional)
* @param $flags Integer Bitfield (optional)
* @return Revision or null
*/
- public static function newFromTitle( $title, $id = 0, $flags = 0 ) {
+ public static function newFromTitle( $title, $id = 0, $flags = null ) {
$conds = array(
'page_namespace' => $title->getNamespace(),
'page_title' => $title->getDBkey()
if ( $id ) {
// Use the specified ID
$conds['rev_id'] = $id;
- } elseif ( !( $flags & self::AVOID_MASTER ) && wfGetLB()->getServerCount() > 1 ) {
- // Get the latest revision ID from the master
- $dbw = wfGetDB( DB_MASTER );
- $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
- if ( $latest === false ) {
- return null; // page does not exist
- }
- $conds['rev_id'] = $latest;
} else {
// Use a join to get the latest revision
$conds[] = 'rev_id=page_latest';
+ // Callers assume this will be up-to-date
+ $flags = is_int( $flags ) ? $flags : self::READ_LATEST; // b/c
}
- return self::newFromConds( $conds, $flags );
+ return self::newFromConds( $conds, (int)$flags );
}
/**
* Returns null if no such revision can be found.
*
* $flags include:
- * IDBAccessObject::LATEST_READ : Select the data from the master
- * IDBAccessObject::LOCKING_READ : Select & lock the data from the master
- * IDBAccessObject::AVOID_MASTER : Avoid master queries; data may be stale
+ * Revision::READ_LATEST : Select the data from the master
+ * Revision::READ_LOCKING : Select & lock the data from the master
*
* @param $revId Integer
* @param $pageId Integer (optional)
* @param $flags Integer Bitfield (optional)
* @return Revision or null
*/
- public static function newFromPageId( $pageId, $revId = 0, $flags = 0 ) {
+ public static function newFromPageId( $pageId, $revId = 0, $flags = null ) {
$conds = array( 'page_id' => $pageId );
if ( $revId ) {
$conds['rev_id'] = $revId;
- } elseif ( !( $flags & self::AVOID_MASTER ) && wfGetLB()->getServerCount() > 1 ) {
- // Get the latest revision ID from the master
- $dbw = wfGetDB( DB_MASTER );
- $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ );
- if ( $latest === false ) {
- return null; // page does not exist
- }
- $conds['rev_id'] = $latest;
} else {
+ // Use a join to get the latest revision
$conds[] = 'rev_id = page_latest';
+ // Callers assume this will be up-to-date
+ $flags = is_int( $flags ) ? $flags : self::READ_LATEST; // b/c
}
- return self::newFromConds( $conds, $flags );
+ return self::newFromConds( $conds, (int)$flags );
}
/**
* @return Revision or null
*/
private static function newFromConds( $conditions, $flags = 0 ) {
- $db = wfGetDB( ( $flags & self::LATEST_READ ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
$rev = self::loadFromConds( $db, $conditions, $flags );
if ( is_null( $rev ) && wfGetLB()->getServerCount() > 1 ) {
- if ( !( $flags & self::LATEST_READ ) && !( $flags & self::AVOID_MASTER ) ) {
+ if ( !( $flags & self::READ_LATEST ) ) {
$dbw = wfGetDB( DB_MASTER );
$rev = self::loadFromConds( $dbw, $conditions, $flags );
}
self::selectUserFields()
);
$options = array( 'LIMIT' => 1 );
- if ( $flags & self::FOR_UPDATE ) {
+ if ( $flags & self::READ_LOCKING ) {
$options[] = 'FOR UPDATE';
}
return $db->select(
// parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
if ( !$bits ||
!isset( $bits['scheme'] ) && strpos( $url, "://" ) !== false ) {
- wfWarn( __METHOD__ . ": Invalid URL: $url" );
+ wfDebug( __METHOD__ . ": Invalid URL: $url" );
return false;
} else {
$scheme = isset( $bits['scheme'] ) ? $bits['scheme'] : null;
if ( in_array( $scheme . '://', $wgUrlProtocols ) ) {
$bits['delimiter'] = '://';
} elseif ( !is_null( $scheme ) && !in_array( $scheme . ':', $wgUrlProtocols ) ) {
- wfWarn( __METHOD__ . ": Invalid scheme in URL: $scheme" );
+ wfDebug( __METHOD__ . ": Invalid scheme in URL: $scheme" );
return false;
} elseif( !is_null( $scheme ) ) {
if( !in_array( $scheme . ':', $wgUrlProtocols ) ) {
foreach ( $components as $name => $value ) {
if ( isset( self::$componentAliases[$name] ) ) {
$canonical = self::$componentAliases[$name];
- wfWarn( __METHOD__ . ": Converting alias $name to canonical $canonical." );
+ wfDebug( __METHOD__ . ": Converting alias $name to canonical $canonical." );
$components[$canonical] = $value;
unset( $components[$name] );
} elseif ( !in_array( $name, self::$validComponents ) ) {
- wfWarn( __METHOD__ . ": $name is not a valid component." );
- unset( $components[$name] );
+ throw new MWException( __METHOD__ . ": $name is not a valid component." );
}
}
// Component is an alias. Get the actual name.
$alias = $name;
$name = self::$componentAliases[$name];
- wfWarn( __METHOD__ . ": Converting alias $alias to canonical $name." );
+ wfDebug( __METHOD__ . ": Converting alias $alias to canonical $name." );
}
if( !in_array( $name, self::$validComponents ) ) {
if ( isset( self::$componentAliases[$name] ) ) {
$alias = $name;
$name = self::$componentAliases[$name];
- wfWarn( __METHOD__ . ": Converting alias $alias to canonical $name." );
+ wfDebug( __METHOD__ . ": Converting alias $alias to canonical $name." );
} elseif ( !in_array( $name, self::$validComponents ) ) {
throw new MWException( __METHOD__ . ": $name is not a valid component." );
}
*
* @internal documentation reviewed 15 Mar 2010
*/
-class WikiPage extends Page {
+class WikiPage extends Page implements IDBAccessObject {
// Constants for $mDataLoadedFrom and related
- /**
- * Data has not been loaded yet (or the object was cleared)
- */
- const DATA_NOT_LOADED = 0;
-
- /**
- * Data has been loaded from a slave database
- */
- const DATA_FROM_SLAVE = 1;
-
- /**
- * Data has been loaded from the master database
- */
- const DATA_FROM_MASTER = 2;
-
- /**
- * Data has been loaded from the master database using FOR UPDATE
- */
- const DATA_FOR_UPDATE = 3;
-
/**
* @var Title
*/
/**@}}*/
/**
- * @var int; one of the DATA_* constants
+ * @var int; one of the READ_* constants
*/
- protected $mDataLoadedFrom = self::DATA_NOT_LOADED;
+ protected $mDataLoadedFrom = self::READ_NONE;
/**
* @var Title
*
* @param $id Int article ID to load
* @param $from string|int one of the following values:
- * - "fromdb" or self::DATA_FROM_SLAVE to select from a slave database
- * - "fromdbmaster" or self::DATA_FROM_MASTER to select from the master database
+ * - "fromdb" or WikiPage::READ_NORMAL to select from a slave database
+ * - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database
*
* @return WikiPage|null
*/
public static function newFromID( $id, $from = 'fromdb' ) {
$from = self::convertSelectType( $from );
- $db = wfGetDB( $from === self::DATA_FROM_MASTER ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_SLAVE );
$row = $db->selectRow( 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ );
if ( !$row ) {
return null;
* @param $row object: database row containing at least fields returned
* by selectFields().
* @param $from string|int: source of $data:
- * - "fromdb" or self::DATA_FROM_SLAVE: from a slave DB
- * - "fromdbmaster" or self::DATA_FROM_MASTER: from the master DB
- * - "forupdate" or self::DATA_FOR_UPDATE: from the master DB using SELECT FOR UPDATE
+ * - "fromdb" or WikiPage::READ_NORMAL: from a slave DB
+ * - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB
+ * - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE
* @return WikiPage
*/
public static function newFromRow( $row, $from = 'fromdb' ) {
}
/**
- * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to DATA_* constants.
+ * Convert 'fromdb', 'fromdbmaster' and 'forupdate' to READ_* constants.
*
* @param $type object|string|int
* @return mixed
private static function convertSelectType( $type ) {
switch ( $type ) {
case 'fromdb':
- return self::DATA_FROM_SLAVE;
+ return self::READ_NORMAL;
case 'fromdbmaster':
- return self::DATA_FROM_MASTER;
+ return self::READ_LATEST;
case 'forupdate':
- return self::DATA_FOR_UPDATE;
+ return self::READ_LOCKING;
default:
// It may already be an integer or whatever else
return $type;
*/
public function clear() {
$this->mDataLoaded = false;
- $this->mDataLoadedFrom = self::DATA_NOT_LOADED;
+ $this->mDataLoadedFrom = self::READ_NONE;
$this->clearCacheFields();
}
*
* @param $from object|string|int One of the following:
* - A DB query result object
- * - "fromdb" or self::DATA_FROM_SLAVE to get from a slave DB
- * - "fromdbmaster" or self::DATA_FROM_MASTER to get from the master DB
- * - "forupdate" or self::DATA_FOR_UPDATE to get from the master DB using SELECT FOR UPDATE
+ * - "fromdb" or WikiPage::READ_NORMAL to get from a slave DB
+ * - "fromdbmaster" or WikiPage::READ_LATEST to get from the master DB
+ * - "forupdate" or WikiPage::READ_LOCKING to get from the master DB using SELECT FOR UPDATE
*
* @return void
*/
return;
}
- if ( $from === self::DATA_FOR_UPDATE ) {
+ if ( $from === self::READ_LOCKING ) {
$data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle, array( 'FOR UPDATE' ) );
- } elseif ( $from === self::DATA_FROM_MASTER ) {
+ } elseif ( $from === self::READ_LATEST ) {
$data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
- } elseif ( $from === self::DATA_FROM_SLAVE ) {
+ } elseif ( $from === self::READ_NORMAL ) {
$data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle );
# Use a "last rev inserted" timestamp key to dimish the issue of slave lag.
# Note that DB also stores the master position in the session and checks it.
$touched = $this->getCachedLastEditTime();
if ( $touched ) { // key set
if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) {
- $from = self::DATA_FROM_MASTER;
+ $from = self::READ_LATEST;
$data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle );
}
}
} else {
// No idea from where the caller got this data, assume slave database.
$data = $from;
- $from = self::DATA_FROM_SLAVE;
+ $from = self::READ_NORMAL;
}
$this->loadFromRow( $data, $from );
* @param $data object: database row containing at least fields returned
* by selectFields()
* @param $from string|int One of the following:
- * - "fromdb" or self::DATA_FROM_SLAVE if the data comes from a slave DB
- * - "fromdbmaster" or self::DATA_FROM_MASTER if the data comes from the master DB
- * - "forupdate" or self::DATA_FOR_UPDATE if the data comes from from
+ * - "fromdb" or WikiPage::READ_NORMAL if the data comes from a slave DB
+ * - "fromdbmaster" or WikiPage::READ_LATEST if the data comes from the master DB
+ * - "forupdate" or WikiPage::READ_LOCKING if the data comes from from
* the master DB using SELECT FOR UPDATE
*/
public function loadFromRow( $data, $from ) {
// also gets the revision row FOR UPDATE; otherwise, it may not find it since a page row
// UPDATE and revision row INSERT by S2 may have happened after the first S1 SELECT.
// http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read.
- $flags = ( $this->mDataLoadedFrom == self::DATA_FOR_UPDATE ) ? Revision::LOCKING_READ : 0;
+ $flags = ( $this->mDataLoadedFrom == self::READ_LOCKING ) ? Revision::READ_LOCKING : 0;
$revision = Revision::newFromPageId( $this->getId(), $latest, $flags );
if ( $revision ) { // sanity
$this->setLastEdit( $revision );
if ( !$oldfile->exists() || !$oldfile->isLocal() || $oldfile->getRedirected() ) {
return array( array( 'nodeleteablefile' ) );
}
- } else {
- $oldfile = false;
}
if ( is_null( $reason ) ) { // Log and RC don't like null reasons
$args = array_merge( array( $params, 'entirewatchlist' ), array_keys( $pageSet->getAllowedParams() ) );
call_user_func_array( array( $this, 'requireOnlyOneParameter' ), $args );
- $db = $this->getDB();
$dbw = $this->getDB( DB_MASTER );
$timestamp = null;
}
// Now, put the valid titles into the result
- $pages = array();
foreach ( $pageSet->getTitles() as $title ) {
$ns = $title->getNamespace();
$dbkey = $title->getDBkey();
* @return array
*/
protected function getApiWarnings() {
- $warnings = array();
-
$warnings = $this->mUpload->checkWarnings();
return $this->transformWarnings( $warnings );
*/
/**
- * Interface for database access objects
+ * Interface for database access objects.
+ *
+ * Classes using this support a set of constants in a bitfield argument to their data loading
+ * functions. In general, objects should assume READ_NORMAL if no flags are explicitly given,
+ * though certain objects may assume READ_LATEST for common use case or legacy reasons.
+ *
+ * There are three types of reads:
+ * - READ_NORMAL : Potentially cached read of data (e.g. from a slave or stale replica)
+ * - READ_LATEST : Up-to-date read as of transaction start (e.g. from master or a quorum read)
+ * - READ_LOCKING : Up-to-date read as of now, that locks the records for the transaction
+ *
+ * Callers should use READ_NORMAL (or pass in no flags) unless the read determines a write.
+ * In theory, such cases may require READ_LOCKING, though to avoid contention, READ_LATEST is
+ * often good enough. If UPDATE race condition checks are required on a row and expensive code
+ * must run after the row is fetched to determine the UPDATE, it may help to do something like:
+ * - a) Read the current row
+ * - b) Determine the new row (expensive, so we don't want to hold locks now)
+ * - c) Re-read the current row with READ_LOCKING; if it changed then bail out
+ * - d) otherwise, do the updates
*/
interface IDBAccessObject {
- const LATEST_READ = 1; // read from the master
- const FOR_UPDATE = 2; // lock the rows read
- const LOCKING_READ = 3; // LATEST_READ | FOR_UPDATE
- const AVOID_MASTER = 4; // avoiding checking the master
+ // Constants for object loading bitfield flags (higher => higher QoS)
+ const READ_LATEST = 1; // read from the master
+ const READ_LOCKING = 3; // READ_LATEST and "FOR UPDATE"
+
+ // Convenience constant for callers to explicitly request slave data
+ const READ_NORMAL = 0; // read from the slave
+
+ // Convenience constant for tracking how data was loaded (higher => higher QoS)
+ const READ_NONE = -1; // not loaded yet (or the object was cleared)
}
return true;
}
- /**
- * Returns true if this database requires that SELECT DISTINCT queries require that all
- ORDER BY expressions occur in the SELECT list per the SQL92 standard
- *
- * @return bool
- */
- function standardSelectDistinct() {
- return true;
- }
-
/**
* Returns true if this database can do a native search on IP columns
* e.g. this works as expected: .. WHERE rc_ip = '127.42.12.102/32';
throw new MWException( 'Database serialization may cause problems, since the connection is not restored on wakeup.' );
}
- /**
- * Same as new DatabaseMysql( ... ), kept for backward compatibility
- * @deprecated since 1.17
- *
- * @param $server
- * @param $user
- * @param $password
- * @param $dbName
- * @param $flags int
- * @return DatabaseMysql
- */
- static function newFromParams( $server, $user, $password, $dbName, $flags = 0 ) {
- wfDeprecated( __METHOD__, '1.17' );
- return new DatabaseMysql( $server, $user, $password, $dbName, $flags );
- }
-
- /**
- * Same as new factory( ... ), kept for backward compatibility
- * @deprecated since 1.18
- * @see Database::factory()
- * @return DatabaseBase
- */
- public final static function newFromType( $dbType, $p = array() ) {
- wfDeprecated( __METHOD__, '1.18' );
- if ( isset( $p['tableprefix'] ) ) {
- $p['tablePrefix'] = $p['tableprefix'];
- }
- return self::factory( $dbType, $p );
- }
-
/**
* Given a DB type, construct the name of the appropriate child class of
* DatabaseBase. This is designed to replace all of the manual stuff like:
* & = filename; reads the file and inserts as a blob
* (we don't use this though...)
*
- * This function should not be used directly by new code outside of the
- * database classes. The query wrapper functions (select() etc.) should be
- * used instead.
- *
* @param $sql string
* @param $func string
*
* @return array
*/
- function prepare( $sql, $func = 'DatabaseBase::prepare' ) {
+ protected function prepare( $sql, $func = 'DatabaseBase::prepare' ) {
/* MySQL doesn't support prepared statements (yet), so just
pack up the query for reference. We'll manually replace
the bits later. */
* Free a prepared query, generated by prepare().
* @param $prepared
*/
- function freePrepared( $prepared ) {
+ protected function freePrepared( $prepared ) {
/* No-op by default */
}
}
/**
- * Prepare & execute an SQL statement, quoting and inserting arguments
- * in the appropriate places.
+ * For faking prepared SQL statements on DBs that don't support it directly.
*
- * This function should not be used directly by new code outside of the
- * database classes. The query wrapper functions (select() etc.) should be
- * used instead.
- *
- * @param $query String
- * @param $args ...
- *
- * @return ResultWrapper
- */
- function safeQuery( $query, $args = null ) {
- $prepared = $this->prepare( $query, 'DatabaseBase::safeQuery' );
-
- if ( !is_array( $args ) ) {
- # Pull the var args
- $args = func_get_args();
- array_shift( $args );
- }
-
- $retval = $this->execute( $prepared, $args );
- $this->freePrepared( $prepared );
-
- return $retval;
- }
-
- /**
- * For faking prepared SQL statements on DBs that don't support
- * it directly.
* @param $preparedQuery String: a 'preparable' SQL statement
* @param $args Array of arguments to fill it with
* @return string executable SQL
* @param $matches Array
* @return String
*/
- function fillPreparedArg( $matches ) {
+ protected function fillPreparedArg( $matches ) {
switch( $matches[1] ) {
case '\\?': return '?';
case '\\!': return '!';
*
* @param $res Mixed: A SQL result
*/
- function freeResult( $res ) {
- }
-
- /**
- * Simple UPDATE wrapper.
- * Usually throws a DBQueryError on failure.
- * If errors are explicitly ignored, returns success
- *
- * This function exists for historical reasons, DatabaseBase::update() has a more standard
- * calling convention and feature set
- *
- * @param $table string
- * @param $var
- * @param $value
- * @param $cond
- * @param $fname string
- *
- * @return bool
- */
- function set( $table, $var, $value, $cond, $fname = 'DatabaseBase::set' ) {
- $table = $this->tableName( $table );
- $sql = "UPDATE $table SET $var = '" .
- $this->strencode( $value ) . "' WHERE ($cond)";
-
- return (bool)$this->query( $sql, $fname );
- }
+ public function freeResult( $res ) {}
/**
* A SELECT wrapper which returns a single field from a single result row.
/**
* The equivalent of DatabaseBase::select() except that the constructed SQL
- * is returned, instead of being immediately executed.
+ * is returned, instead of being immediately executed. This can be useful for
+ * doing UNION queries, where the SQL text of each query is needed. In general,
+ * however, callers outside of Database classes should just use select().
*
* @param $table string|array Table name
* @param $vars string|array Field names
$fname = 'DatabaseBase::estimateRowCount', $options = array() )
{
$rows = 0;
- $res = $this->select ( $table, 'COUNT(*) AS rowcount', $conds, $fname, $options );
+ $res = $this->select( $table, 'COUNT(*) AS rowcount', $conds, $fname, $options );
if ( $res ) {
$row = $this->fetchRow( $res );
* @param $options array
* @return string
*/
- function makeInsertOptions( $options ) {
+ protected function makeInsertOptions( $options ) {
return implode( ' ', $options );
}
* @param $options Array: The options passed to DatabaseBase::update
* @return string
*/
- function makeUpdateOptions( $options ) {
+ protected function makeUpdateOptions( $options ) {
if ( !is_array( $options ) ) {
$options = array( $options );
}
}
/**
- * Bitwise operations
+ * Return aggregated value alias
+ *
+ * @param $valuedata
+ * @param $valuename string
+ *
+ * @return string
*/
+ public function aggregateValue( $valuedata, $valuename = 'value' ) {
+ return $valuename;
+ }
/**
* @param $field
return "($fieldLeft | $fieldRight)";
}
+ /**
+ * Build a concatenation list to feed into a SQL query
+ * @param $stringList Array: list of raw SQL expressions; caller is responsible for any quoting
+ * @return String
+ */
+ public function buildConcat( $stringList ) {
+ return 'CONCAT(' . implode( ',', $stringList ) . ')';
+ }
+
/**
* Change the current database
*
*
* @return string
*/
- function indexName( $index ) {
+ protected function indexName( $index ) {
// Backwards-compatibility hack
$renamed = array(
'ar_usertext_timestamp' => 'usertext_timestamp',
return $name[0] == '"' && substr( $name, -1, 1 ) == '"';
}
- /**
- * Backwards compatibility, identifier quoting originated in DatabasePostgres
- * which used quote_ident which does not follow our naming conventions
- * was renamed to addIdentifierQuotes.
- * @deprecated since 1.18 use addIdentifierQuotes
- *
- * @param $s string
- *
- * @return string
- */
- function quote_ident( $s ) {
- wfDeprecated( __METHOD__, '1.18' );
- return $this->addIdentifierQuotes( $s );
- }
-
- /**
- * Escape string for safe LIKE usage.
- * WARNING: you should almost never use this function directly,
- * instead use buildLike() that escapes everything automatically
- * @deprecated since 1.17, warnings in 1.17, removed in ???
- *
- * @param $s string
- *
- * @return string
- */
- public function escapeLike( $s ) {
- wfDeprecated( __METHOD__, '1.17' );
- return $this->escapeLikeInternal( $s );
- }
-
/**
* @param $s string
* @return string
* If the result of the query is not ordered, then the rows to be returned
* are theoretically arbitrary.
*
- * $sql is expected to be a SELECT, if that makes a difference. For
- * UPDATE, limitResultForUpdate should be used.
+ * $sql is expected to be a SELECT, if that makes a difference.
*
* The version provided by default works in MySQL and SQLite. It will very
* likely need to be overridden for most other DBMSes.
if ( !is_numeric( $limit ) ) {
throw new DBUnexpectedError( $this, "Invalid non-numeric limit passed to limitResult()\n" );
}
-
return "$sql LIMIT "
- . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" )
- . "{$limit} ";
- }
-
- /**
- * @param $sql
- * @param $num
- * @return string
- */
- function limitResultForUpdate( $sql, $num ) {
- return $this->limitResult( $sql, $num, 0 );
+ . ( ( is_numeric( $offset ) && $offset != 0 ) ? "{$offset}," : "" )
+ . "{$limit} ";
}
/**
}
}
- /**
- * Return aggregated value alias
- *
- * @param $valuedata
- * @param $valuename string
- *
- * @return string
- */
- function aggregateValue ( $valuedata, $valuename = 'value' ) {
- return $valuename;
- }
-
/**
* Ping the server and try to reconnect if it there is no connection
*
return $b;
}
- /**
- * Override database's default connection timeout
- *
- * @param $timeout Integer in seconds
- * @return void
- * @deprecated since 1.19; use setSessionOptions()
- */
- public function setTimeout( $timeout ) {
- wfDeprecated( __METHOD__, '1.19' );
- $this->setSessionOptions( array( 'connTimeout' => $timeout ) );
- }
-
/**
* Override database's default behavior. $options include:
* 'connTimeout' : Set the connection timeout value in seconds.
return $this->indexName( $matches[1] );
}
- /**
- * Build a concatenation list to feed into a SQL query
- * @param $stringList Array: list of raw SQL expressions; caller is responsible for any quoting
- * @return String
- */
- function buildConcat( $stringList ) {
- return 'CONCAT(' . implode( ',', $stringList ) . ')';
- }
-
/**
* Check to see if a named lock is available. This is non-blocking.
*
*/
public function __construct( $db, $result, $num_rows, $sql, $columns ){
$this->db = $db;
-
+
if( $result instanceof ResultWrapper ){
$this->result = $result->result;
}
else{
$this->result = $result;
}
-
+
$this->num_rows = $num_rows;
$this->current_pos = 0;
if ( $this->num_rows > 0 ) {
// Make a lower-case list of the column names
// By default, DB2 column names are capitalized
// while MySQL column names are lowercase
-
+
// Is there a reasonable maximum value for $i?
// Setting to 2048 to prevent an infinite loop
for( $i = 0; $i < 2048; $i++ ) {
else {
return false;
}
-
+
$this->columns[$i] = strtolower( $name );
}
}
-
+
$this->sql = $sql;
}
* @return mixed Object on success, false on failure.
*/
public function fetchObject() {
- if ( $this->result
- && $this->num_rows > 0
- && $this->current_pos >= 0
- && $this->current_pos < $this->num_rows )
+ if ( $this->result
+ && $this->num_rows > 0
+ && $this->current_pos >= 0
+ && $this->current_pos < $this->num_rows )
{
$row = $this->fetchRow();
$ret = new stdClass();
-
+
foreach ( $row as $k => $v ) {
$lc = $this->columns[$k];
$ret->$lc = $v;
* @throws DBUnexpectedError
*/
public function fetchRow(){
- if ( $this->result
- && $this->num_rows > 0
- && $this->current_pos >= 0
+ if ( $this->result
+ && $this->num_rows > 0
+ && $this->current_pos >= 0
&& $this->current_pos < $this->num_rows )
{
if ( $this->loadedLines <= $this->current_pos ) {
if ( $this->loadedLines > $this->current_pos ){
return $this->resultSet[$this->current_pos++];
}
-
+
}
return false;
}
return 'ibm_db2';
}
- /**
+ /**
* Returns the database connection object
* @return Object
*/
$res2 = parent::select( $table, $vars2, $conds, $fname, $options2,
$join_conds );
-
+
$obj = $this->fetchObject( $res2 );
$this->mNumRows = $obj->num_rows;
-
+
return new ResultWrapper( $this, new IBM_DB2Result( $this, $res, $obj->num_rows, $vars, $sql ) );
}
######################################
# Unimplemented and not applicable
######################################
- /**
- * Not implemented
- * @return string $sql
- */
- public function limitResultForUpdate( $sql, $num ) {
- $this->installPrint( 'Not implemented for DB2: limitResultForUpdate()' );
- return $sql;
- }
/**
* Only useful with fake prepare like in base Database class
return $res;
}
- /**
- * Prepare & execute an SQL statement, quoting and inserting arguments
- * in the appropriate places.
- * @param $query String
- * @param $args ...
- * @return Resource
- */
- public function safeQuery( $query, $args = null ) {
- // copied verbatim from Database.php
- $prepared = $this->prepare( $query, 'DB2::safeQuery' );
- if( !is_array( $args ) ) {
- # Pull the var args
- $args = func_get_args();
- array_shift( $args );
- }
- $retval = $this->execute( $prepared, $args );
- $this->freePrepared( $prepared );
- return $retval;
- }
-
/**
* For faking prepared SQL statements on DBs that don't support
* it directly.
return $sql;
}
- // MSSQL does support this, but documentation is too thin to make a generalized
- // function for this. Apparently UPDATE TOP (N) works, but the sort order
- // may not be what we're expecting so the top n results may be a random selection.
- // TODO: Implement properly.
- function limitResultForUpdate( $sql, $num ) {
- return $sql;
- }
-
function timestamp( $ts = 0 ) {
return wfTimestamp( TS_ISO_8601, $ts );
}
return '[http://www.mysql.com/ MySQL]';
}
- /**
- * @return bool
- */
- function standardSelectDistinct() {
- return false;
- }
-
/**
* @param $options array
*/
}
}
- /* Not even sure why this is used in the main codebase... */
- function limitResultForUpdate( $sql, $num ) {
- return $sql;
- }
-
/* defines must comply with ^define\s*([^\s=]*)\s*=\s?'\{\$([^\}]*)\}'; */
function sourceStream( $fp, $lineCallback = false, $resultCallback = false,
$fname = 'DatabaseOracle::sourceStream', $inputCallback = false ) {
return pg_field_type( $res, $index );
}
- /* Not even sure why this is used in the main codebase... */
- function limitResultForUpdate( $sql, $num ) {
- return $sql;
- }
-
/**
* @param $b
* @return Blob
}
$cachedResult = false;
$table = 'dummy_search_test';
-
+
$db = new DatabaseSqliteStandalone( ':memory:' );
if ( $db->query( "CREATE VIRTUAL TABLE $table USING FTS3(dummy_field)", __METHOD__, true ) ) {
/**
* @param $res ResultWrapper
- * @param $n
+ * @param $n
* @return bool
*/
function fieldName( $res, $n ) {
$this->mTrxLevel = 0;
}
- /**
- * @param $sql
- * @param $num
- * @return string
- */
- function limitResultForUpdate( $sql, $num ) {
- return $this->limitResult( $sql, $num );
- }
-
/**
* @param $s string
* @return string
}
return $this->query( $sql, $fname );
}
-
-
+
+
/**
* List all tables on the database
*
'name',
"type='table'"
);
-
+
$endArray = array();
-
- foreach( $result as $table ) {
+
+ foreach( $result as $table ) {
$vars = get_object_vars($table);
$table = array_pop( $vars );
-
+
if( !$prefix || strpos( $table, $prefix ) === 0 ) {
if ( strpos( $table, 'sqlite_' ) !== 0 ) {
$endArray[] = $table;
}
-
+
}
}
-
+
return $endArray;
}
// Load the new revision object
$this->mNewRev = $this->mNewid
? Revision::newFromId( $this->mNewid )
- : Revision::newFromTitle( $this->getTitle(), false, Revision::AVOID_MASTER );
+ : Revision::newFromTitle( $this->getTitle(), false, Revision::READ_NORMAL );
if ( !$this->mNewRev instanceof Revision ) {
return false;
* Make sure remaining locks get cleared for sanity
*/
function __destruct() {
- foreach ( $this->conns as $lockDb => $db ) {
+ foreach ( $this->conns as $db ) {
if ( $db->trxLevel() ) { // in transaction
try {
$db->rollback( __METHOD__ ); // finish transaction and kill any rows
*/
function getDescriptionText() {
global $wgParser;
- $revision = Revision::newFromTitle( $this->title, false, Revision::AVOID_MASTER );
+ $revision = Revision::newFromTitle( $this->title, false, Revision::READ_NORMAL );
if ( !$revision ) return false;
$text = $revision->getText();
if ( !$text ) return false;
wfGetLB()->waitFor( $this->params['masterPos'] );
}
- $revision = Revision::newFromTitle( $this->title, 0, Revision::AVOID_MASTER );
+ $revision = Revision::newFromTitle( $this->title, 0, Revision::READ_NORMAL );
if ( !$revision ) {
$this->error = 'refreshLinks: Article not found "' .
$this->title->getPrefixedDBkey() . '"';
}
# Re-parse each page that transcludes this page and update their tracking links...
foreach ( $titles as $title ) {
- $revision = Revision::newFromTitle( $title, 0, Revision::AVOID_MASTER );
+ $revision = Revision::newFromTitle( $title, 0, Revision::READ_NORMAL );
if ( !$revision ) {
$this->error = 'refreshLinks: Article not found "' .
$title->getPrefixedDBkey() . '"';
public function getIRCActionText() {
$this->plaintext = true;
$this->irctext = true;
- $text = $this->getActionText();
$entry = $this->entry;
$parameters = $entry->getParameters();
* @return Boolean: success
*/
static function write( $id, $data ) {
- self::getCache()->set( self::getKey( $id ), $data, 3600 );
+ global $wgObjectCacheSessionExpiry;
+ self::getCache()->set( self::getKey( $id ), $data, $wgObjectCacheSessionExpiry );
return true;
}
// or {{filepath|300px}}, {{filepath|200x300px}}, {{filepath|nowiki|200x300px}}, {{filepath|200x300px|nowiki}}
public static function filepath( $parser, $name='', $argA='', $argB='' ) {
$file = wfFindFile( $name );
- $isNowiki = false;
if( $argA == 'nowiki' ) {
// {{filepath: | option [| size] }}
# Get the revision
$rev = $id
? Revision::newFromId( $id )
- : Revision::newFromTitle( $title, 0, Revision::AVOID_MASTER );
+ : Revision::newFromTitle( $title, 0, Revision::READ_NORMAL );
$rev_id = $rev ? $rev->getId() : 0;
# If there is no current revision, there is no page
if ( $id === false && !$rev ) {
$this->mTitle = $title;
if ( !is_null( $this->mTitle ) ) {
$this->mRevision = Revision::newFromTitle(
- $this->mTitle, false, Revision::AVOID_MASTER );
+ $this->mTitle, false, Revision::READ_NORMAL );
if ( $this->mTitle->getNamespace() === NS_FILE )
$this->mImage = wfFindFile( $this->mTitle );
}
$page = $this->msg( 'booksources' )->inContentLanguage()->text();
$title = Title::makeTitleSafe( NS_PROJECT, $page ); # Show list in content language
if( is_object( $title ) && $title->exists() ) {
- $rev = Revision::newFromTitle( $title, false, Revision::AVOID_MASTER );
+ $rev = Revision::newFromTitle( $title, false, Revision::READ_NORMAL );
$this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $rev->getText() ) );
return true;
}
if ( count( $fields ) > 1 && $count > 30 ) {
$this->toc = Linker::tocIndent();
$tocLength = 0;
- foreach( $fields as $key => $data ) {
+ foreach( $fields as $data ) {
# strip out the 'ns' prefix from the section name:
$ns = substr( $data['section'], 2 );
$query = array( 'wpCookieCheck' => $type );
if ( $this->mReturnTo ) {
$query['returnto'] = $this->mReturnTo;
+ $query['returntoquery'] = $this->mReturnToQuery;
}
$check = $titleObj->getFullURL( $query );
// Output a copy of this first to chunk 0 location:
$status = $this->outputChunk( $this->mLocalFile->getPath() );
-
+
// Update db table to reflect initial "chunk" state
$this->updateChunkStatus();
return $this->mLocalFile;
$this->mUpload = $webRequestUpload;
// Get the chunk status form the db:
$this->getChunkStatus();
-
+
$metadata = $this->stash->getMetadata( $key );
$this->initializePathInfo( $name,
$this->getRealPath( $metadata['us_path'] ),
false
);
}
-
+
/**
* Append the final chunk and ready file for parent::performUpload()
* @return FileRepoStatus
}
return $status;
}
-
+
/**
* Update the chunk db table with the current status:
*/
__METHOD__
);
}
+
/**
* Get the chunk db state and populate update relevant local values
*/
$this->mVirtualTempPath = $row->us_path;
}
}
+
/**
* Get the current Chunk index
* @return Integer index of the current chunk
}
return 0;
}
-
+
/**
* Gets the current offset in fromt the stashedupload table
* @return Integer current byte offset of the chunk file set
}
return 0;
}
-
+
/**
* Output the chunk to disk
*
$idField = $isSqlite ? 'INTEGER' : 'INT unsigned';
$primaryKey = $isSqlite ? 'PRIMARY KEY AUTOINCREMENT' : 'auto_increment PRIMARY KEY';
- $dbw->safeQuery(
+ $dbw->query(
'CREATE TABLE IF NOT EXISTS ' . $dbw->tableName( 'orm_test' ) . '(
test_id ' . $idField . ' NOT NULL ' . $primaryKey . ',
test_name VARCHAR(255) NOT NULL,