Example #1
0
 public function testAddQuotesStringQuote()
 {
     $check = "'string''s cause trouble'";
     if ($this->db->getType() === 'mysql') {
         $check = "'string\\'s cause trouble'";
     }
     $this->assertEquals($check, $this->db->addQuotes("string's cause trouble"));
 }
Example #2
0
 /**
  * Check and repair the destination fields in a link table
  * @param string $table The link table name
  * @param string $fieldPrefix The field prefix in the link table
  * @param int $ns Destination namespace id
  * @param string $name
  * @param array $options Associative array of validated command-line options
  * @param array $extraConds Extra conditions for the SQL query
  */
 private function checkLinkTable($table, $fieldPrefix, $ns, $name, $options, $extraConds = [])
 {
     $batchConds = [];
     $fromField = "{$fieldPrefix}_from";
     $namespaceField = "{$fieldPrefix}_namespace";
     $titleField = "{$fieldPrefix}_title";
     $batchSize = 500;
     while (true) {
         $res = $this->db->select($table, [$fromField, $namespaceField, $titleField], array_merge($batchConds, $extraConds, [$namespaceField => 0, $titleField . $this->db->buildLike("{$name}:", $this->db->anyString())]), __METHOD__, ['ORDER BY' => [$titleField, $fromField], 'LIMIT' => $batchSize]);
         if ($res->numRows() == 0) {
             break;
         }
         foreach ($res as $row) {
             $logTitle = "from={$row->{$fromField}} ns={$row->{$namespaceField}} " . "dbk={$row->{$titleField}}";
             $destTitle = $this->getDestinationTitle($ns, $name, $row->{$namespaceField}, $row->{$titleField}, $options);
             $this->totalLinks++;
             if (!$destTitle) {
                 $this->output("{$table} {$logTitle} *** INVALID\n");
                 continue;
             }
             $this->resolvableLinks++;
             if (!$options['fix']) {
                 $this->output("{$table} {$logTitle} -> " . $destTitle->getPrefixedDBkey() . " DRY RUN\n");
                 continue;
             }
             $this->db->update($table, [$namespaceField => $destTitle->getNamespace(), $titleField => $destTitle->getDBkey()], [$namespaceField => 0, $titleField => $row->{$titleField}, $fromField => $row->{$fromField}], __METHOD__, ['IGNORE']);
             $this->output("{$table} {$logTitle} -> " . $destTitle->getPrefixedDBkey() . "\n");
         }
         $encLastTitle = $this->db->addQuotes($row->{$titleField});
         $encLastFrom = $this->db->addQuotes($row->{$fromField});
         $batchConds = ["{$titleField} > {$encLastTitle} " . "OR ({$titleField} = {$encLastTitle} AND {$fromField} > {$encLastFrom})"];
         wfWaitForSlaves();
     }
 }
 protected function buildUpdateCondition(Database $dbw)
 {
     $rcNew = $dbw->addQuotes(RC_NEW);
     $rcSrcNew = $dbw->addQuotes(RecentChange::SRC_NEW);
     $rcEdit = $dbw->addQuotes(RC_EDIT);
     $rcSrcEdit = $dbw->addQuotes(RecentChange::SRC_EDIT);
     $rcLog = $dbw->addQuotes(RC_LOG);
     $rcSrcLog = $dbw->addQuotes(RecentChange::SRC_LOG);
     $rcExternal = $dbw->addQuotes(RC_EXTERNAL);
     $rcSrcExternal = $dbw->addQuotes(RecentChange::SRC_EXTERNAL);
     return "rc_source = CASE\n\t\t\t\t\tWHEN rc_type = {$rcNew} THEN {$rcSrcNew}\n\t\t\t\t\tWHEN rc_type = {$rcEdit} THEN {$rcSrcEdit}\n\t\t\t\t\tWHEN rc_type = {$rcLog} THEN {$rcSrcLog}\n\t\t\t\t\tWHEN rc_type = {$rcExternal} THEN {$rcSrcExternal}\n\t\t\t\t\tELSE ''\n\t\t\t\tEND";
 }
Example #4
0
 protected function tearDown()
 {
     global $wgRequest, $wgSQLMode;
     $status = ob_get_status();
     if (isset($status['name']) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier') {
         ob_end_flush();
     }
     $this->called['tearDown'] = true;
     // Cleaning up temporary files
     foreach ($this->tmpFiles as $fileName) {
         if (is_file($fileName) || is_link($fileName)) {
             unlink($fileName);
         } elseif (is_dir($fileName)) {
             wfRecursiveRemoveDir($fileName);
         }
     }
     if ($this->needsDB() && $this->db) {
         // Clean up open transactions
         while ($this->db->trxLevel() > 0) {
             $this->db->rollback(__METHOD__, 'flush');
         }
         if ($this->db->getType() === 'mysql') {
             $this->db->query("SET sql_mode = " . $this->db->addQuotes($wgSQLMode));
         }
     }
     // Restore mw globals
     foreach ($this->mwGlobals as $key => $value) {
         $GLOBALS[$key] = $value;
     }
     $this->mwGlobals = [];
     $this->restoreLoggers();
     if (self::$serviceLocator && MediaWikiServices::getInstance() !== self::$serviceLocator) {
         MediaWikiServices::forceGlobalInstance(self::$serviceLocator);
     }
     // TODO: move global state into MediaWikiServices
     RequestContext::resetMain();
     if (session_id() !== '') {
         session_write_close();
         session_id('');
     }
     $wgRequest = new FauxRequest();
     MediaWiki\Session\SessionManager::resetCache();
     MediaWiki\Auth\AuthManager::resetCache();
     $phpErrorLevel = intval(ini_get('error_reporting'));
     if ($phpErrorLevel !== $this->phpErrorLevel) {
         ini_set('error_reporting', $this->phpErrorLevel);
         $oldHex = strtoupper(dechex($this->phpErrorLevel));
         $newHex = strtoupper(dechex($phpErrorLevel));
         $message = "PHP error_reporting setting was left dirty: " . "was 0x{$oldHex} before test, 0x{$newHex} after test!";
         $this->fail($message);
     }
     parent::tearDown();
 }
Example #5
0
 /**
  * Update CategoryLinks collation
  */
 protected function doCollationUpdate()
 {
     global $wgCategoryCollation;
     if ($this->db->fieldExists('categorylinks', 'cl_collation', __METHOD__)) {
         if ($this->db->selectField('categorylinks', 'COUNT(*)', 'cl_collation != ' . $this->db->addQuotes($wgCategoryCollation), __METHOD__) == 0) {
             $this->output("...collations up-to-date.\n");
             return;
         }
         $this->output("Updating category collations...");
         $task = $this->maintenance->runChild('UpdateCollation');
         $task->execute();
         $this->output("...done.\n");
     }
 }
Example #6
0
 /**
  * Copy all rows from $srcTable to $dstTable
  * @param string $srcTable
  * @param string $dstTable
  */
 function sync($srcTable, $dstTable)
 {
     $batchSize = 1000;
     $minTs = $this->dbw->selectField($srcTable, 'MIN(log_timestamp)', false, __METHOD__);
     $minTsUnix = wfTimestamp(TS_UNIX, $minTs);
     $numRowsCopied = 0;
     while (true) {
         $maxTs = $this->dbw->selectField($srcTable, 'MAX(log_timestamp)', false, __METHOD__);
         $copyPos = $this->dbw->selectField($dstTable, 'MAX(log_timestamp)', false, __METHOD__);
         $maxTsUnix = wfTimestamp(TS_UNIX, $maxTs);
         $copyPosUnix = wfTimestamp(TS_UNIX, $copyPos);
         if ($copyPos === null) {
             $percent = 0;
         } else {
             $percent = ($copyPosUnix - $minTsUnix) / ($maxTsUnix - $minTsUnix) * 100;
         }
         printf("%s  %.2f%%\n", $copyPos, $percent);
         # Handle all entries with timestamp equal to $copyPos
         if ($copyPos !== null) {
             $numRowsCopied += $this->copyExactMatch($srcTable, $dstTable, $copyPos);
         }
         # Now copy a batch of rows
         if ($copyPos === null) {
             $conds = false;
         } else {
             $conds = ['log_timestamp > ' . $this->dbw->addQuotes($copyPos)];
         }
         $srcRes = $this->dbw->select($srcTable, '*', $conds, __METHOD__, ['LIMIT' => $batchSize, 'ORDER BY' => 'log_timestamp']);
         if (!$srcRes->numRows()) {
             # All done
             break;
         }
         $batch = [];
         foreach ($srcRes as $srcRow) {
             $batch[] = (array) $srcRow;
         }
         $this->dbw->insert($dstTable, $batch, __METHOD__);
         $numRowsCopied += count($batch);
         wfWaitForSlaves();
     }
     echo "Copied {$numRowsCopied} rows\n";
 }
Example #7
0
 public function addQuotes($s)
 {
     if (is_bool($s)) {
         // Parent would transform to int, which does not play nice with MySQL type juggling.
         // When searching for an int in a string column, the strings are cast to int, which
         // means false would match any string not starting with a number.
         $s = (string) (int) $s;
     }
     return parent::addQuotes($s);
 }
$pendingDBs = $wgMemc->get($mckey);
if (!$pendingDBs) {
    $pendingDBs = array();
    # Cross-reference DBs by master DB server
    $dbsByMaster = array();
    $defaultMaster = isset($wgAlternateMaster['DEFAULT']) ? $wgAlternateMaster['DEFAULT'] : $wgDBserver;
    foreach ($wgLocalDatabases as $db) {
        if (isset($wgAlternateMaster[$db])) {
            $dbsByMaster[$wgAlternateMaster[$db]][] = $db;
        } else {
            $dbsByMaster[$defaultMaster][] = $db;
        }
    }
    foreach ($dbsByMaster as $master => $dbs) {
        $dbConn = new Database($master, $wgDBuser, $wgDBpassword, $dbs[0]);
        $stype = $dbConn->addQuotes($type);
        # Padding row for MySQL bug
        $sql = "(SELECT '-------------------------------------------')";
        foreach ($dbs as $dbName) {
            if ($sql != '') {
                $sql .= ' UNION ';
            }
            if ($type === false) {
                $sql .= "(SELECT '{$dbName}' FROM `{$dbName}`.job LIMIT 1)";
            } else {
                $sql .= "(SELECT '{$dbName}' FROM `{$dbName}`.job WHERE job_cmd={$stype} LIMIT 1)";
            }
        }
        $res = $dbConn->query($sql, 'nextJobDB.php');
        $row = $dbConn->fetchRow($res);
        // discard padding row
Example #9
0
 /**
  * @param string|Blob $s
  * @return string
  */
 public function addQuotes($s)
 {
     if ($s instanceof MssqlBlob) {
         return $s->fetch();
     } elseif ($s instanceof Blob) {
         // this shouldn't really ever be called, but it's here if needed
         // (and will quite possibly make the SQL error out)
         $blob = new MssqlBlob($s->fetch());
         return $blob->fetch();
     } else {
         if (is_bool($s)) {
             $s = $s ? 1 : 0;
         }
         return parent::addQuotes($s);
     }
 }
 protected function populateRevisionOrArchive(Database $dbw, $table, $ns)
 {
     $prefix = $table === 'archive' ? 'ar' : 'rev';
     $model_column = "{$prefix}_content_model";
     $format_column = "{$prefix}_content_format";
     $key = "{$prefix}_id";
     if ($table === 'archive') {
         $selectTables = 'archive';
         $fields = ['ar_namespace', 'ar_title'];
         $join_conds = [];
         $where = $ns === 'all' ? [] : ['ar_namespace' => $ns];
     } else {
         // revision
         $selectTables = ['revision', 'page'];
         $fields = ['page_title', 'page_namespace'];
         $join_conds = ['page' => ['INNER JOIN', 'rev_page=page_id']];
         $where = $ns === 'all' ? [] : ['page_namespace' => $ns];
     }
     $toSave = [];
     $lastId = 0;
     do {
         $rows = $dbw->select($selectTables, array_merge($fields, [$model_column, $format_column, $key]), [$model_column => null, "{$key} > " . $dbw->addQuotes($lastId)] + $where, __METHOD__, ['LIMIT' => $this->mBatchSize, 'ORDER BY' => "{$key} ASC"], $join_conds);
         $this->output("Fetched {$rows->numRows()} rows.\n");
         foreach ($rows as $row) {
             if ($table === 'archive') {
                 $title = Title::makeTitle($row->ar_namespace, $row->ar_title);
             } else {
                 $title = Title::newFromRow($row);
             }
             $lastId = $row->{$key};
             try {
                 $handler = ContentHandler::getForTitle($title);
             } catch (MWException $e) {
                 $this->error("Invalid content model for {$title}");
                 continue;
             }
             $defaultModel = $handler->getModelID();
             $defaultFormat = $handler->getDefaultFormat();
             $dbModel = $row->{$model_column};
             $dbFormat = $row->{$format_column};
             $id = $row->{$key};
             if ($dbModel === null && $dbFormat === null) {
                 // Set the defaults
                 $toSave[$defaultModel][] = $row->{$key};
             } else {
                 // $dbModel === null, $dbFormat set.
                 if ($dbFormat === $defaultFormat) {
                     $toSave[$defaultModel][] = $row->{$key};
                 } else {
                     // non-default format, just update now
                     $this->output("Updating model to match format for {$table} {$id} of {$title}... ");
                     $dbw->update($table, [$model_column => $defaultModel], [$key => $id], __METHOD__);
                     wfWaitForSlaves();
                     $this->output("done.\n");
                     continue;
                 }
             }
             if (count($toSave[$defaultModel]) >= $this->mBatchSize) {
                 $this->updateRevisionOrArchiveRows($dbw, $toSave[$defaultModel], $defaultModel, $table);
                 unset($toSave[$defaultModel]);
             }
         }
     } while ($rows->numRows() >= $this->mBatchSize);
     foreach ($toSave as $model => $ids) {
         $this->updateRevisionOrArchiveRows($dbw, $ids, $model, $table);
     }
 }
 /**
  * @param Database $dbw
  * @return array
  */
 function getConditions($dbw)
 {
     $conds = [];
     $end = $this->getOption('end', false);
     $mime = $this->getOption('mime', false);
     $mediatype = $this->getOption('mediatype', false);
     $like = $this->getOption('metadata-contains', false);
     if ($end !== false) {
         $conds[] = 'img_name <= ' . $dbw->addQuotes($end);
     }
     if ($mime !== false) {
         list($major, $minor) = File::splitMime($mime);
         $conds['img_major_mime'] = $major;
         if ($minor !== '*') {
             $conds['img_minor_mime'] = $minor;
         }
     }
     if ($mediatype !== false) {
         $conds['img_media_type'] = $mediatype;
     }
     if ($like) {
         $conds[] = 'img_metadata ' . $dbw->buildLike($dbw->anyString(), $like, $dbw->anyString());
     }
     return $conds;
 }
Example #12
0
 /**
  * @param Database $db
  * @param string $ip
  * @param string $xfor
  * @return array conditions
  */
 function getIpConds($db, $ip, $xfor = false)
 {
     $type = $xfor ? 'xff' : 'ip';
     // IPv4 CIDR, 16-32 bits
     if (preg_match('#^(\\d+\\.\\d+\\.\\d+\\.\\d+)/(\\d+)$#', $ip, $matches)) {
         if ($matches[2] < 16 || $matches[2] > 32) {
             return array('cuc_' . $type . '_hex' => -1);
         }
         list($start, $end) = IP::parseRange($ip);
         return array('cuc_' . $type . '_hex BETWEEN ' . $db->addQuotes($start) . ' AND ' . $db->addQuotes($end));
     } else {
         if (preg_match('#^\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}/(\\d+)$#', $ip, $matches)) {
             // IPv6 CIDR, 64-128 bits
             if ($matches[1] < 64 || $matches[1] > 128) {
                 return array('cuc_' . $type . '_hex' => -1);
             }
             list($start, $end) = IP::parseRange6($ip);
             return array('cuc_' . $type . '_hex BETWEEN ' . $db->addQuotes($start) . ' AND ' . $db->addQuotes($end));
         } else {
             if (preg_match('#^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$#', $ip)) {
                 // 32 bit IPv4
                 $ip_hex = IP::toHex($ip);
                 return array('cuc_' . $type . '_hex' => $ip_hex);
             } else {
                 if (preg_match('#^\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}:\\w{1,4}$#', $ip)) {
                     // 128 bit IPv6
                     $ip_hex = IP::toHex($ip);
                     return array('cuc_' . $type . '_hex' => $ip_hex);
                 } else {
                     // throw away this query, incomplete IP, these don't get through the entry point anyway
                     return array('cuc_' . $type . '_hex' => -1);
                 }
             }
         }
     }
 }
Example #13
0
 /**
  * Return an SQL expression selecting rows which sort above the given row,
  * assuming an ordering of cl_collation, cl_to, cl_type, cl_from
  * @param stdClass $row
  * @param Database $dbw
  * @return string
  */
 function getBatchCondition($row, $dbw)
 {
     if ($this->hasOption('previous-collation')) {
         $fields = ['cl_to', 'cl_type', 'cl_from'];
     } else {
         $fields = ['cl_collation', 'cl_to', 'cl_type', 'cl_from'];
     }
     $first = true;
     $cond = false;
     $prefix = false;
     foreach ($fields as $field) {
         if ($dbw->getType() === 'mysql' && $field === 'cl_type') {
             // Range conditions with enums are weird in mysql
             // This must be a numeric literal, or it won't work.
             $encValue = intval($row->cl_type_numeric);
         } else {
             $encValue = $dbw->addQuotes($row->{$field});
         }
         $inequality = "{$field} > {$encValue}";
         $equality = "{$field} = {$encValue}";
         if ($first) {
             $cond = $inequality;
             $prefix = $equality;
             $first = false;
         } else {
             $cond .= " OR ({$prefix} AND {$inequality})";
             $prefix .= " AND {$equality}";
         }
     }
     return $cond;
 }