* @return array
* @since 1.18
*/
- function getQueryInfo() {
+ public function getQueryInfo() {
return null;
}
* @return bool
* @since 1.18
*/
- function usesTimestamps() {
+ public function usesTimestamps() {
return false;
}
*
* @return bool
*/
- function isExpensive() {
+ public function isExpensive() {
return $this->getConfig()->get( 'DisableQueryPages' );
}
*
* @return bool
*/
- function isCached() {
+ public function isCached() {
return $this->isExpensive() && $this->getConfig()->get( 'MiserMode' );
}
* @throws DBError|Exception
* @return bool|int
*/
- function recache( $limit, $ignoreErrors = true ) {
+ public function recache( $limit, $ignoreErrors = true ) {
if ( !$this->isCacheable() ) {
return 0;
}
* @return ResultWrapper
* @since 1.18
*/
- function reallyDoQuery( $limit, $offset = false ) {
+ public function reallyDoQuery( $limit, $offset = false ) {
$fname = get_class( $this ) . "::reallyDoQuery";
$dbr = $this->getRecacheDB();
$query = $this->getQueryInfo();
* @param int|bool $limit
* @return ResultWrapper
*/
- function doQuery( $offset = false, $limit = false ) {
+ public function doQuery( $offset = false, $limit = false ) {
if ( $this->isCached() && $this->isCacheable() ) {
return $this->fetchFromCache( $limit, $offset );
} else {
* @return ResultWrapper
* @since 1.18
*/
- function fetchFromCache( $limit, $offset = false ) {
+ public function fetchFromCache( $limit, $offset = false ) {
$dbr = wfGetDB( DB_SLAVE );
$options = array();
if ( $limit !== false ) {
} else {
$options['ORDER BY'] = 'qc_value ASC';
}
- $res = $dbr->select( 'querycache', array( 'qc_type',
+ return $dbr->select( 'querycache', array( 'qc_type',
'namespace' => 'qc_namespace',
'title' => 'qc_title',
'value' => 'qc_value' ),
array( 'qc_type' => $this->getName() ),
__METHOD__, $options
);
- return $dbr->resultObject( $res );
}
public function getCachedTimestamp() {
* Returns limit and offset, as returned by $this->getRequest()->getLimitOffset().
* Subclasses may override this to further restrict or modify limit and offset.
*
+ * @note Restricts the offset parameter, as most query pages have inefficient paging
* @since 1.26
*
* @return int[] list( $limit, $offset )
*/
protected function getLimitOffset() {
- return $this->getRequest()->getLimitOffset();
+ list( $limit, $offset ) = $this->getRequest()->getLimitOffset();
+ if ( !$this->getConfig()->get( 'MiserMode' ) ) {
+ $maxResults = $this->getMaxResults();
+ // Can't display more than max results on a page
+ $limit = min( $limit, $maxResults );
+ // Can't skip over more than $maxResults
+ $offset = min( $offset, $maxResults );
+ // Can't let $offset + $limit > $maxResults
+ $limit = min( $limit, $maxResults - $offset );
+ }
+ return array( $limit, $offset );
+ }
+
+ /**
+ * Get max number of results we can return in miser mode.
+ *
+ * Most QueryPage subclasses use inefficient paging, so limit the max amount we return
+ * This matters for uncached query pages that might otherwise accept an offset of 3 million
+ *
+ * @since 1.27
+ * @return int
+ */
+ protected function getMaxResults() {
+ // Max of 10000, unless we store more than 5000 in query cache.
+ return max( $this->getConfig()->get( 'QueryCacheLimit' ), 10000 );
}
/**
* real, honest-to-gosh query page.
* @param string $par
*/
- function execute( $par ) {
+ public function execute( $par ) {
$user = $this->getUser();
if ( !$this->userCanExecute( $user ) ) {
$this->displayRestrictionError();
min( $this->numRows, $this->limit ), # do not show the one extra row, if exist
$this->offset + 1, ( min( $this->numRows, $this->limit ) + $this->offset ) )->parseAsBlock() );
# Disable the "next" link when we reach the end
+ $atEnd = ( $this->numRows <= $this->limit )
+ || ( $this->offset + $this-> limit >= $this->getMaxResults() );
$paging = $this->getLanguage()->viewPrevNext( $this->getPageTitle( $par ), $this->offset,
- $this->limit, $this->linkParameters(), ( $this->numRows <= $this->limit ) );
+ $this->limit, $this->linkParameters(), $atEnd );
$out->addHTML( '<p>' . $paging . '</p>' );
} else {
# No results to show, so don't bother with "showing X of Y" etc.