mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Fixes #2160: SphinxQL does not support OFFSET
Improved `QueryBuilder::buildLimit()` to support big numbers
This commit is contained in:
@ -5,6 +5,7 @@ Yii Framework 2 sphinx extension Change Log
|
||||
----------------------------
|
||||
|
||||
- Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder)
|
||||
- Bug #2160: SphinxQL does not support OFFSET (qiangxue, romeo7)
|
||||
- Enh #1398: Refactor ActiveRecord to use BaseActiveRecord class of the framework (klimov-paul)
|
||||
|
||||
2.0.0 alpha, December 1, 2013
|
||||
|
@ -509,13 +509,16 @@ class QueryBuilder extends Object
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
$sql = '';
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql = 'LIMIT ' . (int)$limit;
|
||||
if (is_integer($offset) && $offset > 0 || is_string($offset) && ctype_digit($offset) && $offset !== '0') {
|
||||
$sql = 'LIMIT ' . $offset;
|
||||
}
|
||||
if ($offset > 0) {
|
||||
$sql .= ' OFFSET ' . (int)$offset;
|
||||
if (is_string($limit) && ctype_digit($limit) || is_integer($limit) && $limit >= 0) {
|
||||
$sql = $sql === '' ? "LIMIT $limit" : "$sql,$limit";
|
||||
} elseif ($sql !== '') {
|
||||
$sql .= ',1000'; // this is the default limit by sphinx
|
||||
}
|
||||
return ltrim($sql);
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@ Yii Framework 2 Change Log
|
||||
- Bug #1998: Unchecked required checkbox never pass client validation (klevron)
|
||||
- Bug #2084: AssetController adjusting CSS URLs declared at same line fixed (klimov-paul)
|
||||
- Bug #2091: `QueryBuilder::buildInCondition()` fails to handle array not starting with index 0 (qiangxue)
|
||||
- Bug #2160: SphinxQL does not support OFFSET (qiangxue, romeo7)
|
||||
- Bug #2212: `yii\gridview\DataColumn` generates incorrect labels when used with nosql DB and there is no data (qiangxue)
|
||||
- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark)
|
||||
- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark)
|
||||
@ -112,6 +113,7 @@ Yii Framework 2 Change Log
|
||||
- Enh: Added support for using timeZone with `yii\base\Formatter` (dizews)
|
||||
- Enh: Added `yii\web\View::POS_LOAD` (qiangxue)
|
||||
- Enh: Added `yii\web\Response::clearOutputBuffers()` (qiangxue)
|
||||
- Enh: Improved `QueryBuilder::buildLimit()` to support big numbers (qiangxue)
|
||||
- Chg #1519: `yii\web\User::loginRequired()` now returns the `Response` object instead of exiting the application (qiangxue)
|
||||
- Chg #1586: `QueryBuilder::buildLikeCondition()` will now escape special characters and use percentage characters by default (qiangxue)
|
||||
- Chg #1610: `Html::activeCheckboxList()` and `Html::activeRadioList()` will submit an empty string if no checkbox/radio is selected (qiangxue)
|
||||
|
@ -720,15 +720,35 @@ class QueryBuilder extends \yii\base\Object
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
$sql = '';
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql = 'LIMIT ' . (int)$limit;
|
||||
if ($this->hasLimit($limit)) {
|
||||
$sql = 'LIMIT ' . $limit;
|
||||
}
|
||||
if ($offset > 0) {
|
||||
$sql .= ' OFFSET ' . (int)$offset;
|
||||
if ($this->hasOffset($offset)) {
|
||||
$sql .= ' OFFSET ' . $offset;
|
||||
}
|
||||
return ltrim($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given limit is effective.
|
||||
* @param mixed $limit the given limit
|
||||
* @return boolean whether the limit is effective
|
||||
*/
|
||||
protected function hasLimit($limit)
|
||||
{
|
||||
return is_string($limit) && ctype_digit($limit) || is_integer($limit) && $limit >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given offset is effective.
|
||||
* @param mixed $offset the given offset
|
||||
* @return boolean whether the offset is effective
|
||||
*/
|
||||
protected function hasOffset($offset)
|
||||
{
|
||||
return is_integer($offset) && $offset > 0 || is_string($offset) && ctype_digit($offset) && $offset !== '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $unions
|
||||
* @param array $params the binding parameters to be populated
|
||||
|
@ -77,13 +77,13 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
// limit is not optional in CUBRID
|
||||
// http://www.cubrid.org/manual/90/en/LIMIT%20Clause
|
||||
// "You can specify a very big integer for row_count to display to the last row, starting from a specific row."
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql = 'LIMIT ' . (int)$limit;
|
||||
if ($offset > 0) {
|
||||
$sql .= ' OFFSET ' . (int)$offset;
|
||||
if ($this->hasLimit($limit)) {
|
||||
$sql = 'LIMIT ' . $limit;
|
||||
if ($this->hasOffset($offset)) {
|
||||
$sql .= ' OFFSET ' . $offset;
|
||||
}
|
||||
} elseif ($offset > 0) {
|
||||
$sql = 'LIMIT 9223372036854775807 OFFSET ' . (int)$offset; // 2^63-1
|
||||
} elseif ($this->hasOffset($offset)) {
|
||||
$sql = "LIMIT 9223372036854775807 OFFSET $offset"; // 2^63-1
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
@ -56,14 +56,18 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
*/
|
||||
public function buildLimit($limit, $offset = 0)
|
||||
{
|
||||
$sql = '';
|
||||
if ($offset !== null && $offset >= 0) {
|
||||
$sql = 'OFFSET ' . (int)$offset . ' ROWS';
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql .= ' FETCH NEXT ' . (int)$limit . ' ROWS ONLY';
|
||||
}
|
||||
$hasOffset = $this->hasOffset($offset);
|
||||
$hasLimit = $this->hasLimit($limit);
|
||||
if ($hasOffset || $hasLimit) {
|
||||
// http://technet.microsoft.com/en-us/library/gg699618.aspx
|
||||
$sql = 'OFFSET ' . ($hasOffset ? $offset : '0');
|
||||
if ($hasLimit) {
|
||||
$sql .= " FETCH NEXT $limit ROWS ONLY";
|
||||
}
|
||||
return $sql;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// public function resetSequence($table, $value = null)
|
||||
|
@ -147,17 +147,18 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
$sql = '';
|
||||
if ($this->hasLimit($limit)) {
|
||||
$sql = 'LIMIT ' . $limit;
|
||||
if ($this->hasOffset($offset)) {
|
||||
$sql .= ' OFFSET ' . $offset;
|
||||
}
|
||||
} elseif ($this->hasOffset($offset)) {
|
||||
// limit is not optional in MySQL
|
||||
// http://stackoverflow.com/a/271650/1106908
|
||||
// http://dev.mysql.com/doc/refman/5.0/en/select.html#idm47619502796240
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql = 'LIMIT ' . (int)$limit;
|
||||
if ($offset > 0) {
|
||||
$sql .= ' OFFSET ' . (int)$offset;
|
||||
}
|
||||
} elseif ($offset > 0) {
|
||||
$sql = 'LIMIT ' . (int)$offset . ', 18446744073709551615'; // 2^64-1
|
||||
$sql = "LIMIT $offset, 18446744073709551615"; // 2^64-1
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
];
|
||||
$this->sql = implode($this->separator, array_filter($clauses));
|
||||
|
||||
if ($query->limit !== null || $query->offset !== null) {
|
||||
$this->sql = $this->buildLimit($query->limit, $query->offset);
|
||||
}
|
||||
|
||||
$unions = $this->buildUnion($query->union, $params);
|
||||
if ($unions !== '') {
|
||||
@ -46,33 +44,27 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
if (($limit < 0) && ($offset < 0)) {
|
||||
return $this->sql;
|
||||
}
|
||||
$filters = [];
|
||||
if ($offset > 0) {
|
||||
$filters[] = 'rowNumId > ' . (int)$offset;
|
||||
if ($this->hasOffset($offset) > 0) {
|
||||
$filters[] = 'rowNumId > ' . $offset;
|
||||
}
|
||||
|
||||
if ($limit >= 0) {
|
||||
$filters[] = 'rownum <= ' . (int)$limit;
|
||||
if ($this->hasLimit($limit)) {
|
||||
$filters[] = 'rownum <= ' . $limit;
|
||||
}
|
||||
|
||||
if (count($filters) > 0) {
|
||||
if (!empty($filters)) {
|
||||
$filter = implode(' and ', $filters);
|
||||
$filter = " WHERE " . $filter;
|
||||
} else {
|
||||
$filter = '';
|
||||
}
|
||||
|
||||
$sql = <<<EOD
|
||||
return <<<EOD
|
||||
WITH USER_SQL AS ({$this->sql}),
|
||||
PAGINATION AS (SELECT USER_SQL.*, rownum as rowNumId FROM USER_SQL)
|
||||
SELECT *
|
||||
FROM PAGINATION
|
||||
{$filter}
|
||||
WHERE $filter
|
||||
EOD;
|
||||
return $sql;
|
||||
} else {
|
||||
return $this->sql;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -260,15 +260,15 @@ class QueryBuilder extends \yii\db\QueryBuilder
|
||||
public function buildLimit($limit, $offset)
|
||||
{
|
||||
$sql = '';
|
||||
if ($this->hasLimit($limit)) {
|
||||
$sql = 'LIMIT ' . $limit;
|
||||
if ($this->hasOffset($offset)) {
|
||||
$sql .= ' OFFSET ' . $offset;
|
||||
}
|
||||
} elseif ($this->hasOffset($offset)) {
|
||||
// limit is not optional in SQLite
|
||||
// http://www.sqlite.org/syntaxdiagrams.html#select-stmt
|
||||
if ($limit !== null && $limit >= 0) {
|
||||
$sql = 'LIMIT ' . (int)$limit;
|
||||
if ($offset > 0) {
|
||||
$sql .= ' OFFSET ' . (int)$offset;
|
||||
}
|
||||
} elseif ($offset > 0) {
|
||||
$sql = 'LIMIT 9223372036854775807 OFFSET ' . (int)$offset; // 2^63-1
|
||||
$sql = "LIMIT 9223372036854775807 OFFSET $offset"; // 2^63-1
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
Reference in New Issue
Block a user