(bug 20275) Fixed LIKE queries on SQLite backend
* All manually built LIKE queries in the core are replaced with a wrapper function Database::buildLike() * This function automatically performs all escaping, so Database::escapeLike() is now almost never used
This commit is contained in:
parent
f215649e2d
commit
ae57ab1eec
33 changed files with 219 additions and 56 deletions
|
|
@ -581,6 +581,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
|
|||
dummy
|
||||
* (bug 21161) Changing $wgCacheEpoch now always invalidates file cache
|
||||
* (bug 20268) Fixed row count estimation on SQLite backend
|
||||
* (bug 20275) Fixed LIKE queries on SQLite backend
|
||||
|
||||
== API changes in 1.16 ==
|
||||
|
||||
|
|
|
|||
|
|
@ -343,6 +343,7 @@ $wgAutoloadLocalClasses = array(
|
|||
'LBFactory' => 'includes/db/LBFactory.php',
|
||||
'LBFactory_Multi' => 'includes/db/LBFactory_Multi.php',
|
||||
'LBFactory_Simple' => 'includes/db/LBFactory.php',
|
||||
'LikeMatch' => 'includes/db/Database.php',
|
||||
'LoadBalancer' => 'includes/db/LoadBalancer.php',
|
||||
'LoadMonitor' => 'includes/db/LoadMonitor.php',
|
||||
'LoadMonitor_MySQL' => 'includes/db/LoadMonitor.php',
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ class Block {
|
|||
$options = array();
|
||||
$db =& $this->getDBOptions( $options );
|
||||
$conds = array(
|
||||
"ipb_range_start LIKE '$range%'",
|
||||
'ipb_range_start' . $db->buildLike( $range, $db->anyString() ),
|
||||
"ipb_range_start <= '$iaddr'",
|
||||
"ipb_range_end >= '$iaddr'"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ class LinkFilter {
|
|||
* @static
|
||||
* @param $filterEntry String: domainparts
|
||||
* @param $prot String: protocol
|
||||
* @deprecated Use makeLikeArray() and pass result to Database::buildLike() instead
|
||||
*/
|
||||
public static function makeLike( $filterEntry , $prot = 'http://' ) {
|
||||
wfDeprecated( __METHOD__ );
|
||||
$db = wfGetDB( DB_MASTER );
|
||||
if ( substr( $filterEntry, 0, 2 ) == '*.' ) {
|
||||
$subdomains = true;
|
||||
|
|
@ -105,4 +107,99 @@ class LinkFilter {
|
|||
}
|
||||
return $like;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an array to be used for calls to Database::like(), which will match the specified
|
||||
* string. There are several kinds of filter entry:
|
||||
* *.domain.com - Produces http://com.domain.%, matches domain.com
|
||||
* and www.domain.com
|
||||
* domain.com - Produces http://com.domain./%, matches domain.com
|
||||
* or domain.com/ but not www.domain.com
|
||||
* *.domain.com/x - Produces http://com.domain.%/x%, matches
|
||||
* www.domain.com/xy
|
||||
* domain.com/x - Produces http://com.domain./x%, matches
|
||||
* domain.com/xy but not www.domain.com/xy
|
||||
*
|
||||
* Asterisks in any other location are considered invalid.
|
||||
*
|
||||
* @static
|
||||
* @param $filterEntry String: domainparts
|
||||
* @param $prot String: protocol
|
||||
*/
|
||||
public static function makeLikeArray( $filterEntry , $prot = 'http://' ) {
|
||||
$db = wfGetDB( DB_MASTER );
|
||||
if ( substr( $filterEntry, 0, 2 ) == '*.' ) {
|
||||
$subdomains = true;
|
||||
$filterEntry = substr( $filterEntry, 2 );
|
||||
if ( $filterEntry == '' ) {
|
||||
// We don't want to make a clause that will match everything,
|
||||
// that could be dangerous
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$subdomains = false;
|
||||
}
|
||||
// No stray asterisks, that could cause confusion
|
||||
// It's not simple or efficient to handle it properly so we don't
|
||||
// handle it at all.
|
||||
if ( strpos( $filterEntry, '*' ) !== false ) {
|
||||
return false;
|
||||
}
|
||||
$slash = strpos( $filterEntry, '/' );
|
||||
if ( $slash !== false ) {
|
||||
$path = substr( $filterEntry, $slash );
|
||||
$host = substr( $filterEntry, 0, $slash );
|
||||
} else {
|
||||
$path = '/';
|
||||
$host = $filterEntry;
|
||||
}
|
||||
// Reverse the labels in the hostname, convert to lower case
|
||||
// For emails reverse domainpart only
|
||||
if ( $prot == 'mailto:' && strpos($host, '@') ) {
|
||||
// complete email adress
|
||||
$mailparts = explode( '@', $host );
|
||||
$domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
|
||||
$host = $domainpart . '@' . $mailparts[0];
|
||||
$like = array( "$prot$host", $db->anyString() );
|
||||
} elseif ( $prot == 'mailto:' ) {
|
||||
// domainpart of email adress only. do not add '.'
|
||||
$host = strtolower( implode( '.', array_reverse( explode( '.', $host ) ) ) );
|
||||
$like = array( "$prot$host", $db->anyString() );
|
||||
} else {
|
||||
$host = strtolower( implode( '.', array_reverse( explode( '.', $host ) ) ) );
|
||||
if ( substr( $host, -1, 1 ) !== '.' ) {
|
||||
$host .= '.';
|
||||
}
|
||||
$like = array( "$prot$host" );
|
||||
|
||||
if ( $subdomains ) {
|
||||
$like[] = $db->anyString();
|
||||
}
|
||||
if ( !$subdomains || $path !== '/' ) {
|
||||
$like[] = $path;
|
||||
$like[] = $db->anyString();
|
||||
}
|
||||
}
|
||||
return $like;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters an array returned by makeLikeArray(), removing everything past first pattern placeholder.
|
||||
* @static
|
||||
* @param $arr array: array to filter
|
||||
* @return filtered array
|
||||
*/
|
||||
public static function keepOneWildcard( $arr ) {
|
||||
if( !is_array( $arr ) ) {
|
||||
return $arr;
|
||||
}
|
||||
|
||||
foreach( $arr as $key => $value ) {
|
||||
if ( $value instanceof LikeMatch ) {
|
||||
return array_slice( $arr, 0, $key + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -854,6 +854,8 @@ class LogPager extends ReverseChronologicalPager {
|
|||
|
||||
$this->title = $title->getPrefixedText();
|
||||
$ns = $title->getNamespace();
|
||||
$db = $this->mDb;
|
||||
|
||||
# Using the (log_namespace, log_title, log_timestamp) index with a
|
||||
# range scan (LIKE) on the first two parts, instead of simple equality,
|
||||
# makes it unusable for sorting. Sorted retrieval using another index
|
||||
|
|
@ -866,10 +868,8 @@ class LogPager extends ReverseChronologicalPager {
|
|||
# log entries for even the busiest pages, so it can be safely scanned
|
||||
# in full to satisfy an impossible condition on user or similar.
|
||||
if( $pattern && !$wgMiserMode ) {
|
||||
# use escapeLike to avoid expensive search patterns like 't%st%'
|
||||
$safetitle = $this->mDb->escapeLike( $title->getDBkey() );
|
||||
$this->mConds['log_namespace'] = $ns;
|
||||
$this->mConds[] = "log_title LIKE '$safetitle%'";
|
||||
$this->mConds[] = 'log_title ' . $db->buildLike( $title->getDBkey(), $db->anyString() );
|
||||
$this->pattern = $pattern;
|
||||
} else {
|
||||
$this->mConds['log_namespace'] = $ns;
|
||||
|
|
@ -877,9 +877,9 @@ class LogPager extends ReverseChronologicalPager {
|
|||
}
|
||||
// Paranoia: avoid brute force searches (bug 17342)
|
||||
if( !$wgUser->isAllowed( 'deletedhistory' ) ) {
|
||||
$this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::DELETED_ACTION) . ' = 0';
|
||||
$this->mConds[] = $db->bitAnd('log_deleted', LogPage::DELETED_ACTION) . ' = 0';
|
||||
} else if( !$wgUser->isAllowed( 'suppressrevision' ) ) {
|
||||
$this->mConds[] = $this->mDb->bitAnd('log_deleted', LogPage::SUPPRESSED_ACTION) .
|
||||
$this->mConds[] = $db->bitAnd('log_deleted', LogPage::SUPPRESSED_ACTION) .
|
||||
' != ' . LogPage::SUPPRESSED_ACTION;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,12 +318,11 @@ class MessageCache {
|
|||
# database or in code.
|
||||
if ( $code !== $wgContLanguageCode ) {
|
||||
# Messages for particular language
|
||||
$escapedCode = $dbr->escapeLike( $code );
|
||||
$conds[] = "page_title like '%%/$escapedCode'";
|
||||
$conds[] = 'page_title' . $dbr->buildLike( $dbr->anyString(), "/$code" );
|
||||
} else {
|
||||
# Effectively disallows use of '/' character in NS_MEDIAWIKI for uses
|
||||
# other than language code.
|
||||
$conds[] = "page_title not like '%%/%%'";
|
||||
$conds[] = 'page_title NOT' . $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1663,8 +1663,7 @@ class Title {
|
|||
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$conds['page_namespace'] = $this->getNamespace();
|
||||
$conds[] = 'page_title LIKE ' . $dbr->addQuotes(
|
||||
$dbr->escapeLike( $this->getDBkey() ) . '/%' );
|
||||
$conds[] = 'page_title ' . $dbr->buildLike( $this->getDBkey() . '/', $dbr->anyString() );
|
||||
$options = array();
|
||||
if( $limit > -1 )
|
||||
$options['LIMIT'] = $limit;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class ApiQueryAllCategories extends ApiQueryGeneratorBase {
|
|||
$from = (is_null($params['from']) ? null : $this->titlePartToKey($params['from']));
|
||||
$this->addWhereRange('cat_title', $dir, $from, null);
|
||||
if (isset ($params['prefix']))
|
||||
$this->addWhere("cat_title LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'");
|
||||
$this->addWhere('cat_title' . $db->buildLike( $this->titlePartToKey($params['prefix']), $db->anyString() ) );
|
||||
|
||||
$this->addOption('LIMIT', $params['limit']+1);
|
||||
$this->addOption('ORDER BY', 'cat_title' . ($params['dir'] == 'descending' ? ' DESC' : ''));
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class ApiQueryAllLinks extends ApiQueryGeneratorBase {
|
|||
if (!is_null($params['from']))
|
||||
$this->addWhere('pl_title>=' . $db->addQuotes($this->titlePartToKey($params['from'])));
|
||||
if (isset ($params['prefix']))
|
||||
$this->addWhere("pl_title LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'");
|
||||
$this->addWhere('pl_title' . $db->buildLike( $this->titlePartToKey($params['prefix']), $db->anyString() ) );
|
||||
|
||||
$this->addFields(array (
|
||||
'pl_title',
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class ApiQueryAllUsers extends ApiQueryBase {
|
|||
$this->addWhere('u1.user_name >= ' . $db->addQuotes($this->keyToTitle($params['from'])));
|
||||
|
||||
if (!is_null($params['prefix']))
|
||||
$this->addWhere('u1.user_name LIKE "' . $db->escapeLike($this->keyToTitle( $params['prefix'])) . '%"');
|
||||
$this->addWhere('u1.user_name' . $db->buildLike($this->keyToTitle($params['prefix']), $db->anyString()));
|
||||
|
||||
if (!is_null($params['group'])) {
|
||||
// Filter only users that belong to a given group
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class ApiQueryAllimages extends ApiQueryGeneratorBase {
|
|||
$from = (is_null($params['from']) ? null : $this->titlePartToKey($params['from']));
|
||||
$this->addWhereRange('img_name', $dir, $from, null);
|
||||
if (isset ($params['prefix']))
|
||||
$this->addWhere("img_name LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'");
|
||||
$this->addWhere('img_name' . $db->buildLike( $this->titlePartToKey($params['prefix']), $db->anyString() ) );
|
||||
|
||||
if (isset ($params['minsize'])) {
|
||||
$this->addWhere('img_size>=' . intval($params['minsize']));
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class ApiQueryAllpages extends ApiQueryGeneratorBase {
|
|||
$from = (is_null($params['from']) ? null : $this->titlePartToKey($params['from']));
|
||||
$this->addWhereRange('page_title', $dir, $from, null);
|
||||
if (isset ($params['prefix']))
|
||||
$this->addWhere("page_title LIKE '" . $db->escapeLike($this->titlePartToKey($params['prefix'])) . "%'");
|
||||
$this->addWhere('page_title' . $db->buildLike($this->titlePartToKey($params['prefix']), $db->->anyString()));
|
||||
|
||||
if (is_null($resultPageSet)) {
|
||||
$selectFields = array (
|
||||
|
|
|
|||
|
|
@ -109,8 +109,10 @@ class ApiQueryBlocks extends ApiQueryBase {
|
|||
else
|
||||
$lower = $upper = IP::toHex($params['ip']);
|
||||
$prefix = substr($lower, 0, 4);
|
||||
|
||||
$db = $this->getDB();
|
||||
$this->addWhere(array(
|
||||
"ipb_range_start LIKE '$prefix%'",
|
||||
'ipb_range_start' . $db->buildLike($prefix, $db->anyString()),
|
||||
"ipb_range_start <= '$lower'",
|
||||
"ipb_range_end >= '$upper'"
|
||||
));
|
||||
|
|
|
|||
|
|
@ -77,14 +77,15 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
|
|||
if(is_null($protocol))
|
||||
$protocol = 'http://';
|
||||
|
||||
$likeQuery = LinkFilter::makeLike($query, $protocol);
|
||||
$likeQuery = LinkFilter::makeLikeArray($query, $protocol);
|
||||
if (!$likeQuery)
|
||||
$this->dieUsage('Invalid query', 'bad_query');
|
||||
$likeQuery = substr($likeQuery, 0, strpos($likeQuery,'%')+1);
|
||||
$this->addWhere('el_index LIKE ' . $db->addQuotes( $likeQuery ));
|
||||
|
||||
$likeQuery = LinkFilter::keepOneWildcard($likeQuery);
|
||||
$this->addWhere('el_index ' . $db->buildLike( $likeQuery ));
|
||||
}
|
||||
else if(!is_null($protocol))
|
||||
$this->addWhere('el_index LIKE ' . $db->addQuotes( "$protocol%" ));
|
||||
$this->addWhere('el_index ' . $db->buildLike( "$protocol", $db->anyString() ));
|
||||
|
||||
$prop = array_flip($params['prop']);
|
||||
$fld_ids = isset($prop['ids']);
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class ApiQueryContributions extends ApiQueryBase {
|
|||
$this->addWhere($this->getDB()->bitAnd('rev_deleted',Revision::DELETED_USER) . ' = 0');
|
||||
// We only want pages by the specified users.
|
||||
if($this->prefixMode)
|
||||
$this->addWhere("rev_user_text LIKE '" . $this->getDB()->escapeLike($this->userprefix) . "%'");
|
||||
$this->addWhere('rev_user_text' . $this->getDB()->buildLike($this->userprefix, $this->getDB()->anyString()));
|
||||
else
|
||||
$this->addWhereFld('rev_user_text', $this->usernames);
|
||||
// ... and in the specified timeframe.
|
||||
|
|
|
|||
|
|
@ -1490,7 +1490,9 @@ abstract class DatabaseBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Escape string for safe LIKE usage
|
||||
* Escape string for safe LIKE usage.
|
||||
* WARNING: you should almost never use this function directly,
|
||||
* instead use buildLike() that escapes everything automatically
|
||||
*/
|
||||
function escapeLike( $s ) {
|
||||
$s = str_replace( '\\', '\\\\', $s );
|
||||
|
|
@ -1499,6 +1501,48 @@ abstract class DatabaseBase {
|
|||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* LIKE statement wrapper, receives a variable-length argument list with parts of pattern to match
|
||||
* containing either string literals that will be escaped or tokens returned by anyChar() or anyString().
|
||||
* Alternatively, the function could be provided with an array of aforementioned parameters.
|
||||
*
|
||||
* Example: $dbr->buildLike( 'My_page_title/', $dbr->anyString() ) returns a LIKE clause that searches
|
||||
* for subpages of 'My page title'.
|
||||
* Alternatively: $pattern = array( 'My_page_title/', $dbr->anyString() ); $query .= $dbr->buildLike( $pattern );
|
||||
*
|
||||
* @ return String: fully built LIKE statement
|
||||
*/
|
||||
function buildLike() {
|
||||
$params = func_get_args();
|
||||
if (count($params) > 0 && is_array($params[0])) {
|
||||
$params = $params[0];
|
||||
}
|
||||
|
||||
$s = '';
|
||||
foreach( $params as $value) {
|
||||
if( $value instanceof LikeMatch ) {
|
||||
$s .= $value->toString();
|
||||
} else {
|
||||
$s .= $this->escapeLike( $value );
|
||||
}
|
||||
}
|
||||
return " LIKE '" . $s . "' ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a token for buildLike() that denotes a '_' to be used in a LIKE query
|
||||
*/
|
||||
function anyChar() {
|
||||
return new LikeMatch( '_' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a token for buildLike() that denotes a '%' to be used in a LIKE query
|
||||
*/
|
||||
function anyString() {
|
||||
return new LikeMatch( '%' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an appropriately quoted sequence value for inserting a new row.
|
||||
* MySQL has autoincrement fields, so this is just NULL. But the PostgreSQL
|
||||
|
|
@ -2779,3 +2823,19 @@ class ResultWrapper implements Iterator {
|
|||
return $this->current() !== false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by DatabaseBase::buildLike() to represent characters that have special meaning in SQL LIKE clauses
|
||||
* and thus need no escaping. Don't instantiate it manually, use Database::anyChar() and anyString() instead.
|
||||
*/
|
||||
class LikeMatch {
|
||||
private $str;
|
||||
|
||||
public function __construct( $s ) {
|
||||
$this->str = $s;
|
||||
}
|
||||
|
||||
public function toString() {
|
||||
return $this->str;
|
||||
}
|
||||
}
|
||||
|
|
@ -418,6 +418,14 @@ class DatabaseSqlite extends DatabaseBase {
|
|||
return $s;
|
||||
}
|
||||
|
||||
function buildLike() {
|
||||
$params = func_get_args();
|
||||
if ( count( $params ) > 0 && is_array( $params[0] ) ) {
|
||||
$params = $params[0];
|
||||
}
|
||||
return parent::buildLike( $params ) . "ESCAPE '\' ";
|
||||
}
|
||||
|
||||
/**
|
||||
* How lagged is this slave?
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class LocalRepo extends FSRepo {
|
|||
$ext = File::normalizeExtension($ext);
|
||||
$inuse = $dbw->selectField( 'oldimage', '1',
|
||||
array( 'oi_sha1' => $sha1,
|
||||
"oi_archive_name LIKE '%.{$ext}'",
|
||||
'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(), ".$ext" ),
|
||||
$dbw->bitAnd('oi_deleted', File::DELETED_FILE) => File::DELETED_FILE ),
|
||||
__METHOD__, array( 'FOR UPDATE' ) );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,10 +262,9 @@ class IPUnblockForm {
|
|||
// Fixme -- encapsulate this sort of query-building.
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$encIp = $dbr->addQuotes( IP::sanitizeIP($this->ip) );
|
||||
$encRange = $dbr->addQuotes( "$range%" );
|
||||
$encAddr = $dbr->addQuotes( $iaddr );
|
||||
$conds[] = "(ipb_address = $encIp) OR
|
||||
(ipb_range_start LIKE $encRange AND
|
||||
(ipb_range_start" . $dbr->buildLike( $range, $dbr->anyString() ) . " AND
|
||||
ipb_range_start <= $encAddr
|
||||
AND ipb_range_end >= $encAddr)";
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ class LinkSearchPage extends QueryPage {
|
|||
*/
|
||||
static function mungeQuery( $query , $prot ) {
|
||||
$field = 'el_index';
|
||||
$rv = LinkFilter::makeLike( $query , $prot );
|
||||
$rv = LinkFilter::makeLikeArray( $query , $prot );
|
||||
if ($rv === false) {
|
||||
//makeLike doesn't handle wildcard in IP, so we'll have to munge here.
|
||||
if (preg_match('/^(:?[0-9]{1,3}\.)+\*\s*$|^(:?[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]*\*\s*$/', $query)) {
|
||||
$rv = $prot . rtrim($query, " \t*") . '%';
|
||||
$rv = array( $prot . rtrim($query, " \t*"), $dbr->anyString() );
|
||||
$field = 'el_to';
|
||||
}
|
||||
}
|
||||
|
|
@ -125,8 +125,8 @@ class LinkSearchPage extends QueryPage {
|
|||
|
||||
/* strip everything past first wildcard, so that index-based-only lookup would be done */
|
||||
list( $munged, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
|
||||
$stripped = substr($munged,0,strpos($munged,'%')+1);
|
||||
$encSearch = $dbr->addQuotes( $stripped );
|
||||
$stripped = LinkFilter::keepOneWildcard( $munged );
|
||||
$like = $dbr->buildLike( $stripped );
|
||||
|
||||
$encSQL = '';
|
||||
if ( isset ($this->mNs) && !$wgMiserMode )
|
||||
|
|
@ -144,7 +144,7 @@ class LinkSearchPage extends QueryPage {
|
|||
$externallinks $use_index
|
||||
WHERE
|
||||
page_id=el_from
|
||||
AND $clause LIKE $encSearch
|
||||
AND $clause $like
|
||||
$encSQL";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,8 @@ class ImageListPager extends TablePager {
|
|||
$nt = Title::newFromUrl( $search );
|
||||
if( $nt ) {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$m = $dbr->strencode( strtolower( $nt->getDBkey() ) );
|
||||
$m = str_replace( "%", "\\%", $m );
|
||||
$m = str_replace( "_", "\\_", $m );
|
||||
$this->mQueryConds = array( "LOWER(img_name) LIKE '%{$m}%'" );
|
||||
$this->mQueryConds = array( 'LOWER(img_name)' . $dbr->buildLike( $dbr->anyString(),
|
||||
strtolower( $nt->getDBkey() ), $dbr->anyString() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ class MovePageForm {
|
|||
)
|
||||
) ) {
|
||||
$conds = array(
|
||||
'page_title LIKE '.$dbr->addQuotes( $dbr->escapeLike( $ot->getDBkey() ) . '/%' )
|
||||
'page_title' . $dbr->buildLike( $ot->getDBkey() . '/', $dbr->anyString() )
|
||||
.' OR page_title = ' . $dbr->addQuotes( $ot->getDBkey() )
|
||||
);
|
||||
$conds['page_namespace'] = array();
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ function wfSpecialNewimages( $par, $specialPage ) {
|
|||
if ( $wpIlMatch != '' && !$wgMiserMode) {
|
||||
$nt = Title::newFromUrl( $wpIlMatch );
|
||||
if( $nt ) {
|
||||
$m = $dbr->escapeLike( strtolower( $nt->getDBkey() ) );
|
||||
$where[] = "LOWER(img_name) LIKE '%{$m}%'";
|
||||
$where[] = 'LOWER(img_name) ' . $dbr->buildLike( $dbr->anyString(), strtolower( $nt->getDBkey() ), $dbr->anyString() );
|
||||
$searchpar['wpIlMatch'] = $wpIlMatch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class SpecialPrefixindex extends SpecialAllpages {
|
|||
array( 'page_namespace', 'page_title', 'page_is_redirect' ),
|
||||
array(
|
||||
'page_namespace' => $namespace,
|
||||
'page_title LIKE \'' . $dbr->escapeLike( $prefixKey ) .'%\'',
|
||||
'page_title' . $dbr->buildLike( $prefixKey, $dbr->anyString() ),
|
||||
'page_title >= ' . $dbr->addQuotes( $fromKey ),
|
||||
),
|
||||
__METHOD__,
|
||||
|
|
|
|||
|
|
@ -58,16 +58,15 @@ class PageArchive {
|
|||
$title = Title::newFromText( $prefix );
|
||||
if( $title ) {
|
||||
$ns = $title->getNamespace();
|
||||
$encPrefix = $dbr->escapeLike( $title->getDBkey() );
|
||||
$prefix = $title->getDBkey();
|
||||
} else {
|
||||
// Prolly won't work too good
|
||||
// @todo handle bare namespace names cleanly?
|
||||
$ns = 0;
|
||||
$encPrefix = $dbr->escapeLike( $prefix );
|
||||
}
|
||||
$conds = array(
|
||||
'ar_namespace' => $ns,
|
||||
"ar_title LIKE '$encPrefix%'",
|
||||
'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
|
||||
);
|
||||
return self::listPages( $dbr, $conds );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class WithoutInterwikiPage extends PageQueryPage {
|
|||
function getSQL() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
list( $page, $langlinks ) = $dbr->tableNamesN( 'page', 'langlinks' );
|
||||
$prefix = $this->prefix ? "AND page_title LIKE '" . $dbr->escapeLike( $this->prefix ) . "%'" : '';
|
||||
$prefix = $this->prefix ? 'AND page_title' . $dbr->buildLike( $this->prefix , $dbr->anyString() ) : '';
|
||||
return
|
||||
"SELECT 'Withoutinterwiki' AS type,
|
||||
page_namespace AS namespace,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class CleanupSpam extends Maintenance {
|
|||
$wgUser->addToDatabase();
|
||||
}
|
||||
$spec = $this->getArg();
|
||||
$like = LinkFilter::makeLike( $spec );
|
||||
$like = LinkFilter::makeLikeArray( $spec );
|
||||
if ( !$like ) {
|
||||
$this->error( "Not a valid hostname specification: $spec", true );
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@ class CleanupSpam extends Maintenance {
|
|||
$dbr = wfGetDB( DB_SLAVE, array(), $wikiID );
|
||||
|
||||
$count = $dbr->selectField( 'externallinks', 'COUNT(*)',
|
||||
array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
|
||||
array( 'el_index' . $dbr->buildLike( $like ) ), __METHOD__ );
|
||||
if ( $count ) {
|
||||
$found = true;
|
||||
passthru( "php cleanupSpam.php --wiki='$wikiID' $spec | sed 's/^/$wikiID: /'" );
|
||||
|
|
@ -69,7 +69,7 @@ class CleanupSpam extends Maintenance {
|
|||
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$res = $dbr->select( 'externallinks', array( 'DISTINCT el_from' ),
|
||||
array( 'el_index LIKE ' . $dbr->addQuotes( $like ) ), __METHOD__ );
|
||||
array( 'el_index' . $dbr->buildLike( $like ) ), __METHOD__ );
|
||||
$count = $dbr->numRows( $res );
|
||||
$this->output( "Found $count articles containing $spec\n" );
|
||||
foreach ( $res as $row ) {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ $db = wfGetDB(DB_MASTER);
|
|||
while (1) {
|
||||
wfWaitForSlaves( 2 );
|
||||
$db->commit();
|
||||
$encServer = $db->escapeLike( $wgServer );
|
||||
$q="DELETE /* deleteSelfExternals */ FROM externallinks WHERE el_to LIKE '$encServer/%' LIMIT 1000\n";
|
||||
$q = $db->limitResult( "DELETE /* deleteSelfExternals */ FROM externallinks WHERE el_to"
|
||||
. $db->buildLike( $wgServer . '/', $db->anyString() ), 1000 );
|
||||
print "Deleting a batch\n";
|
||||
$db->query($q);
|
||||
if (!$db->affectedRows()) exit(0);
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ class NamespaceConflictChecker extends Maintenance {
|
|||
$table = $this->db->tableName( $page );
|
||||
|
||||
$prefix = $this->db->strencode( $name );
|
||||
$likeprefix = str_replace( '_', '\\_', $prefix);
|
||||
$encNamespace = $this->db->addQuotes( $ns );
|
||||
|
||||
$titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)";
|
||||
|
|
@ -212,7 +211,7 @@ class NamespaceConflictChecker extends Maintenance {
|
|||
$titleSql AS title
|
||||
FROM {$table}
|
||||
WHERE {$page}_namespace=0
|
||||
AND {$page}_title LIKE '$likeprefix:%'";
|
||||
AND {$page}_title " . $this->db->buildLike( $name . ':', $this-db->anyString() );
|
||||
|
||||
$result = $this->db->query( $sql, __METHOD__ );
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,8 @@ function compressWithConcat( $startId, $maxChunkSize, $beginDate,
|
|||
# overwriting bulk storage concat rows. Don't compress external references, because
|
||||
# the script doesn't yet delete rows from external storage.
|
||||
$conds = array(
|
||||
"old_flags NOT LIKE '%object%' AND old_flags NOT LIKE '%external%'");
|
||||
'old_flags NOT ' . $dbr->buildLike( MATCH_STRING, 'object', MATCH_STRING ) . ' AND old_flags NOT '
|
||||
. $dbr->buildLike( MATCH_STRING, 'external', MATCH_STRING ) );
|
||||
|
||||
if ( $beginDate ) {
|
||||
if ( !preg_match( '/^\d{14}$/', $beginDate ) ) {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ function moveToExternal( $cluster, $maxID, $minID = 1 ) {
|
|||
$res = $dbr->select( 'text', array( 'old_id', 'old_flags', 'old_text' ),
|
||||
array(
|
||||
"old_id BETWEEN $blockStart AND $blockEnd",
|
||||
"old_flags NOT LIKE '%external%'",
|
||||
'old_flags NOT ' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ),
|
||||
), $fname );
|
||||
while ( $row = $dbr->fetchObject( $res ) ) {
|
||||
# Resolve stubs
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ function resolveStub( $id, $stubText, $flags ) {
|
|||
|
||||
# Get the (maybe) external row
|
||||
$externalRow = $dbr->selectRow( 'text', array( 'old_text' ),
|
||||
array( 'old_id' => $stub->mOldId, "old_flags LIKE '%external%'" ),
|
||||
array( 'old_id' => $stub->mOldId, 'old_flags' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ) ),
|
||||
$fname
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class TrackBlobs {
|
|||
if ( $this->textClause != '' ) {
|
||||
$this->textClause .= ' OR ';
|
||||
}
|
||||
$this->textClause .= 'old_text LIKE ' . $dbr->addQuotes( $dbr->escapeLike( "DB://$cluster/" ) . '%' );
|
||||
$this->textClause .= 'old_text' . $dbr->buildLike( "DB://$cluster/", $dbr->anyString() );
|
||||
}
|
||||
}
|
||||
return $this->textClause;
|
||||
|
|
@ -99,7 +99,7 @@ class TrackBlobs {
|
|||
'rev_id > ' . $dbr->addQuotes( $startId ),
|
||||
'rev_text_id=old_id',
|
||||
$textClause,
|
||||
"old_flags LIKE '%external%'",
|
||||
'old_flags ' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ),
|
||||
),
|
||||
__METHOD__,
|
||||
array(
|
||||
|
|
@ -175,7 +175,7 @@ class TrackBlobs {
|
|||
array(
|
||||
'old_id>' . $dbr->addQuotes( $startId ),
|
||||
$textClause,
|
||||
"old_flags LIKE '%external%'",
|
||||
'old_flags ' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ),
|
||||
'bt_text_id IS NULL'
|
||||
),
|
||||
__METHOD__,
|
||||
|
|
|
|||
Loading…
Reference in a new issue