/** * @param IDatabase $db * @return mixed */ public function doQuery($db) { $timestamps = array(); foreach ($this->ids as $id) { $timestamps[] = $db->timestamp($id); } return $db->select('archive', Revision::selectArchiveFields(), array('ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), 'ar_timestamp' => $timestamps), __METHOD__, array('ORDER BY' => 'ar_timestamp DESC')); }
/** * @param IDatabase $db * @return mixed */ public function doQuery($db) { $timestamps = []; foreach ($this->ids as $id) { $timestamps[] = $db->timestamp($id); } $tables = ['archive']; $fields = Revision::selectArchiveFields(); $conds = ['ar_namespace' => $this->title->getNamespace(), 'ar_title' => $this->title->getDBkey(), 'ar_timestamp' => $timestamps]; $join_conds = []; $options = ['ORDER BY' => 'ar_timestamp DESC']; ChangeTags::modifyDisplayQuery($tables, $fields, $conds, $join_conds, $options, ''); return $db->select($tables, $fields, $conds, __METHOD__, $options, $join_conds); }
/** * Invalidate the cache of a list of pages from a single namespace. * This is intended for use by subclasses. * * @param IDatabase $dbw * @param int $namespace Namespace number * @param array $dbkeys */ public static function invalidatePages(IDatabase $dbw, $namespace, array $dbkeys) { if ($dbkeys === []) { return; } $dbw->onTransactionIdle(function () use($dbw, $namespace, $dbkeys) { $services = MediaWikiServices::getInstance(); $lbFactory = $services->getDBLoadBalancerFactory(); // Determine which pages need to be updated. // This is necessary to prevent the job queue from smashing the DB with // large numbers of concurrent invalidations of the same page. $now = $dbw->timestamp(); $ids = $dbw->selectFieldValues('page', 'page_id', ['page_namespace' => $namespace, 'page_title' => $dbkeys, 'page_touched < ' . $dbw->addQuotes($now)], __METHOD__); if (!$ids) { return; } $batchSize = $services->getMainConfig()->get('UpdateRowsPerQuery'); $ticket = $lbFactory->getEmptyTransactionTicket(__METHOD__); foreach (array_chunk($ids, $batchSize) as $idBatch) { $dbw->update('page', ['page_touched' => $now], ['page_id' => $idBatch, 'page_touched < ' . $dbw->addQuotes($now)], __METHOD__); $lbFactory->commitAndWaitForReplication(__METHOD__, $ticket); } }, __METHOD__); }
/** * Update the page record to point to a newly saved revision. * * @param IDatabase $dbw * @param Revision $revision For ID number, and text used to set * length and redirect status fields * @param int $lastRevision If given, will not overwrite the page field * when different from the currently set value. * Giving 0 indicates the new page flag should be set on. * @param bool $lastRevIsRedirect If given, will optimize adding and * removing rows in redirect table. * @return bool Success; false if the page row was missing or page_latest changed */ public function updateRevisionOn($dbw, $revision, $lastRevision = null, $lastRevIsRedirect = null) { global $wgContentHandlerUseDB; // Assertion to try to catch T92046 if ((int) $revision->getId() === 0) { throw new InvalidArgumentException(__METHOD__ . ': Revision has ID ' . var_export($revision->getId(), 1)); } $content = $revision->getContent(); $len = $content ? $content->getSize() : 0; $rt = $content ? $content->getUltimateRedirectTarget() : null; $conditions = ['page_id' => $this->getId()]; if (!is_null($lastRevision)) { // An extra check against threads stepping on each other $conditions['page_latest'] = $lastRevision; } $row = ['page_latest' => $revision->getId(), 'page_touched' => $dbw->timestamp($revision->getTimestamp()), 'page_is_new' => $lastRevision === 0 ? 1 : 0, 'page_is_redirect' => $rt !== null ? 1 : 0, 'page_len' => $len]; if ($wgContentHandlerUseDB) { $row['page_content_model'] = $revision->getContentModel(); } $dbw->update('page', $row, $conditions, __METHOD__); $result = $dbw->affectedRows() > 0; if ($result) { $this->updateRedirectOn($dbw, $rt, $lastRevIsRedirect); $this->setLastEdit($revision); $this->mLatest = $revision->getId(); $this->mIsRedirect = (bool) $rt; // Update the LinkCache. LinkCache::singleton()->addGoodLinkObj($this->getId(), $this->mTitle, $len, $this->mIsRedirect, $this->mLatest, $revision->getContentModel()); } return $result; }
/** * Insert a new revision into the database, returning the new revision ID * number on success and dies horribly on failure. * * @param IDatabase $dbw (master connection) * @throws MWException * @return int */ public function insertOn($dbw) { global $wgDefaultExternalStore, $wgContentHandlerUseDB; // Not allowed to have rev_page equal to 0, false, etc. if (!$this->mPage) { $title = $this->getTitle(); if ($title instanceof Title) { $titleText = ' for page ' . $title->getPrefixedText(); } else { $titleText = ''; } throw new MWException("Cannot insert revision{$titleText}: page ID must be nonzero"); } $this->checkContentModel(); $data = $this->mText; $flags = self::compressRevisionText($data); # Write to external storage if required if ($wgDefaultExternalStore) { // Store and get the URL $data = ExternalStore::insertToDefault($data); if (!$data) { throw new MWException("Unable to store text to external storage"); } if ($flags) { $flags .= ','; } $flags .= 'external'; } # Record the text (or external storage URL) to the text table if ($this->mTextId === null) { $old_id = $dbw->nextSequenceValue('text_old_id_seq'); $dbw->insert('text', array('old_id' => $old_id, 'old_text' => $data, 'old_flags' => $flags), __METHOD__); $this->mTextId = $dbw->insertId(); } if ($this->mComment === null) { $this->mComment = ""; } # Record the edit in revisions $rev_id = $this->mId !== null ? $this->mId : $dbw->nextSequenceValue('revision_rev_id_seq'); $row = array('rev_id' => $rev_id, 'rev_page' => $this->mPage, 'rev_text_id' => $this->mTextId, 'rev_comment' => $this->mComment, 'rev_minor_edit' => $this->mMinorEdit ? 1 : 0, 'rev_user' => $this->mUser, 'rev_user_text' => $this->mUserText, 'rev_timestamp' => $dbw->timestamp($this->mTimestamp), 'rev_deleted' => $this->mDeleted, 'rev_len' => $this->mSize, 'rev_parent_id' => $this->mParentId === null ? $this->getPreviousRevisionId($dbw) : $this->mParentId, 'rev_sha1' => $this->mSha1 === null ? Revision::base36Sha1($this->mText) : $this->mSha1); if ($wgContentHandlerUseDB) { // NOTE: Store null for the default model and format, to save space. // XXX: Makes the DB sensitive to changed defaults. // Make this behavior optional? Only in miser mode? $model = $this->getContentModel(); $format = $this->getContentFormat(); $title = $this->getTitle(); if ($title === null) { throw new MWException("Insufficient information to determine the title of the " . "revision's page!"); } $defaultModel = ContentHandler::getDefaultModelFor($title); $defaultFormat = ContentHandler::getForModelID($defaultModel)->getDefaultFormat(); $row['rev_content_model'] = $model === $defaultModel ? null : $model; $row['rev_content_format'] = $format === $defaultFormat ? null : $format; } $dbw->insert('revision', $row, __METHOD__); $this->mId = $rev_id !== null ? $rev_id : $dbw->insertId(); // Assertion to try to catch T92046 if ((int) $this->mId === 0) { throw new UnexpectedValueException('After insert, Revision mId is ' . var_export($this->mId, 1) . ': ' . var_export($row, 1)); } Hooks::run('RevisionInsertComplete', array(&$this, $data, $flags)); return $this->mId; }
/** * @param IDatabase $db * @return string */ protected function getMaxDateTime($db) { if (time() > 0x7fffffff) { return $db->timestamp(1 << 62); } else { return $db->timestamp(0x7fffffff); } }
/** * Generates condition for the query used in a batch count visiting watchers. * * @param IDatabase $db * @param array $targetsWithVisitThresholds array of pairs (LinkTarget, last visit threshold) * @return string */ private function getVisitingWatchersCondition(IDatabase $db, array $targetsWithVisitThresholds) { $missingTargets = []; $namespaceConds = []; foreach ($targetsWithVisitThresholds as list($target, $threshold)) { if ($threshold === null) { $missingTargets[] = $target; continue; } /* @var LinkTarget $target */ $namespaceConds[$target->getNamespace()][] = $db->makeList(['wl_title = ' . $db->addQuotes($target->getDBkey()), $db->makeList(['wl_notificationtimestamp >= ' . $db->addQuotes($db->timestamp($threshold)), 'wl_notificationtimestamp IS NULL'], LIST_OR)], LIST_AND); } $conds = []; foreach ($namespaceConds as $namespace => $pageConds) { $conds[] = $db->makeList(['wl_namespace = ' . $namespace, '(' . $db->makeList($pageConds, LIST_OR) . ')'], LIST_AND); } if ($missingTargets) { $lb = new LinkBatch($missingTargets); $conds[] = $lb->constructSet('wl', $db); } return $db->makeList($conds, LIST_OR); }
/** * @param IDatabase $dbr * @param string $fname * @return array|bool */ private function loadFieldsWithTimestamp($dbr, $fname) { $fieldMap = false; $row = $dbr->selectRow('image', $this->getLazyCacheFields('img_'), ['img_name' => $this->getName(), 'img_timestamp' => $dbr->timestamp($this->getTimestamp())], $fname); if ($row) { $fieldMap = $this->unprefixRow($row, 'img_'); } else { # File may have been uploaded over in the meantime; check the old versions $row = $dbr->selectRow('oldimage', $this->getLazyCacheFields('oi_'), ['oi_name' => $this->getName(), 'oi_timestamp' => $dbr->timestamp($this->getTimestamp())], $fname); if ($row) { $fieldMap = $this->unprefixRow($row, 'oi_'); } } return $fieldMap; }
private function getStartFromConds(IDatabase $db, array $options) { $op = $options['dir'] === self::DIR_OLDER ? '<' : '>'; list($rcTimestamp, $rcId) = $options['startFrom']; $rcTimestamp = $db->addQuotes($db->timestamp($rcTimestamp)); $rcId = (int) $rcId; return $db->makeList(["rc_timestamp {$op} {$rcTimestamp}", $db->makeList(["rc_timestamp = {$rcTimestamp}", "rc_id {$op}= {$rcId}"], LIST_AND)], LIST_OR); }