Skip to content

Commit 896a352

Browse files
committed
drivers: fixed applyLimit for $limit = 0
1 parent f37328e commit 896a352

16 files changed

+378
-26
lines changed

src/Database/Drivers/MsSqlDriver.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,15 @@ public function formatLike($value, $pos)
7777
*/
7878
public function applyLimit(& $sql, $limit, $offset)
7979
{
80-
if ($limit >= 0) {
80+
if ($offset) {
81+
throw new Nette\NotSupportedException('Offset is not supported by this database.');
82+
83+
} elseif ($limit !== NULL) {
8184
$sql = preg_replace('#^\s*(SELECT(\s+DISTINCT|\s+ALL)?|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
8285
if (!$count) {
8386
throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
8487
}
8588
}
86-
87-
if ($offset) {
88-
throw new Nette\NotSupportedException('Offset is not supported by this database.');
89-
}
9089
}
9190

9291

src/Database/Drivers/MySqlDriver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ public function formatLike($value, $pos)
122122
*/
123123
public function applyLimit(& $sql, $limit, $offset)
124124
{
125-
if ($limit >= 0 || $offset > 0) {
125+
if ($limit !== NULL || $offset > 0) {
126126
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
127-
$sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
127+
$sql .= ' LIMIT ' . ($limit === NULL ? '18446744073709551615' : (int) $limit)
128128
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
129129
}
130130
}

src/Database/Drivers/OciDriver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,10 @@ public function applyLimit(& $sql, $limit, $offset)
104104
if ($offset > 0) {
105105
// see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
106106
$sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
107-
. ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
107+
. ($limit !== NULL ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
108108
. ') WHERE "__rnum" > '. (int) $offset;
109109

110-
} elseif ($limit >= 0) {
110+
} elseif ($limit !== NULL) {
111111
$sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
112112
}
113113
}

src/Database/Drivers/OdbcDriver.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,15 @@ public function formatLike($value, $pos)
7676
*/
7777
public function applyLimit(& $sql, $limit, $offset)
7878
{
79-
if ($limit >= 0) {
79+
if ($offset) {
80+
throw new Nette\NotSupportedException('Offset is not supported by this database.');
81+
82+
} elseif ($limit !== NULL) {
8083
$sql = preg_replace('#^\s*(SELECT(\s+DISTINCT|\s+ALL)?|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
8184
if (!$count) {
8285
throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
8386
}
8487
}
85-
86-
if ($offset) {
87-
throw new Nette\NotSupportedException('Offset is not supported by this database.');
88-
}
8988
}
9089

9190

src/Database/Drivers/PgSqlDriver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function formatLike($value, $pos)
106106
*/
107107
public function applyLimit(& $sql, $limit, $offset)
108108
{
109-
if ($limit >= 0) {
109+
if ($limit !== NULL) {
110110
$sql .= ' LIMIT ' . (int) $limit;
111111
}
112112
if ($offset > 0) {

src/Database/Drivers/SqliteDriver.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ public function formatLike($value, $pos)
112112
*/
113113
public function applyLimit(& $sql, $limit, $offset)
114114
{
115-
if ($limit >= 0 || $offset > 0) {
116-
$sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
115+
if ($limit !== NULL || $offset > 0) {
116+
$sql .= ' LIMIT ' . ($limit === NULL ? '-1' : (int) $limit)
117+
. ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
117118
}
118119
}
119120

src/Database/Drivers/SqlsrvDriver.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,17 @@ public function formatLike($value, $pos)
9393
public function applyLimit(& $sql, $limit, $offset)
9494
{
9595
if (version_compare($this->version, 11, '<')) { // 11 == SQL Server 2012
96-
if ($limit >= 0) {
96+
if ($offset) {
97+
throw new Nette\NotSupportedException('Offset is not supported by this database.');
98+
99+
} elseif ($limit !== NULL) {
97100
$sql = preg_replace('#^\s*(SELECT(\s+DISTINCT|\s+ALL)?|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
98101
if (!$count) {
99102
throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
100103
}
101104
}
102105

103-
if ($offset > 0) {
104-
throw new Nette\NotSupportedException('Offset is not supported by this database.');
105-
}
106-
} elseif ($limit >= 0 || $offset > 0) {
106+
} elseif ($limit !== NULL || $offset > 0) {
107107
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
108108
$sql .= ' OFFSET ' . (int) $offset . ' ROWS '
109109
. 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY';

src/Database/ISupplementalDriver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ function formatLike($value, $pos);
6262
/**
6363
* Injects LIMIT/OFFSET to the SQL query.
6464
* @param string SQL query that will be modified.
65-
* @param int
66-
* @param int
65+
* @param int|NULL
66+
* @param int|NULL
6767
* @return void
6868
*/
6969
function applyLimit(& $sql, $limit, $offset);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
use Tester\Assert;
4+
5+
require __DIR__ . '/../../bootstrap.php';
6+
7+
8+
$driver = new Nette\Database\Drivers\MsSqlDriver;
9+
10+
Assert::exception(function () use ($driver) {
11+
$query = 'SELECT 1 FROM t';
12+
$driver->applyLimit($query, 10, 20);
13+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
14+
15+
Assert::exception(function () use ($driver) {
16+
$query = 'SELECT 1 FROM t';
17+
$driver->applyLimit($query, 0, 20);
18+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
19+
20+
$query = 'SELECT 1 FROM t';
21+
$driver->applyLimit($query, 10, 0);
22+
Assert::same('SELECT TOP 10 1 FROM t', $query);
23+
24+
Assert::exception(function () use ($driver) {
25+
$query = 'SELECT 1 FROM t';
26+
$driver->applyLimit($query, NULL, 20);
27+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
28+
29+
$query = 'SELECT 1 FROM t';
30+
$driver->applyLimit($query, 10, NULL);
31+
Assert::same('SELECT TOP 10 1 FROM t', $query);
32+
33+
$query = ' select distinct 1 FROM t';
34+
$driver->applyLimit($query, 10, NULL);
35+
Assert::same(' select distinct TOP 10 1 FROM t', $query);
36+
37+
$query = 'UPDATE t SET';
38+
$driver->applyLimit($query, 10, NULL);
39+
Assert::same('UPDATE TOP 10 t SET', $query);
40+
41+
$query = 'DELETE FROM t SET';
42+
$driver->applyLimit($query, 10, NULL);
43+
Assert::same('DELETE TOP 10 FROM t SET', $query);
44+
45+
Assert::exception(function () use ($driver) {
46+
$query = 'SET FROM t';
47+
$driver->applyLimit($query, 10, NULL);
48+
}, Nette\InvalidArgumentException::class, 'SQL query must begin with SELECT, UPDATE or DELETE command.');
49+
50+
$query = 'SELECT 1 FROM t';
51+
$driver->applyLimit($query, -1, NULL);
52+
Assert::same('SELECT TOP -1 1 FROM t', $query);
53+
54+
Assert::exception(function () use ($driver) {
55+
$query = 'SELECT 1 FROM t';
56+
$driver->applyLimit($query, NULL, -1);
57+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/**
4+
* @dataProvider? ../databases.ini mysql
5+
*/
6+
7+
use Tester\Assert;
8+
9+
require __DIR__ . '/../connect.inc.php'; // create $connection
10+
11+
12+
$driver = $connection->getSupplementalDriver();
13+
14+
$query = 'SELECT 1 FROM t';
15+
$driver->applyLimit($query, 10, 20);
16+
Assert::same('SELECT 1 FROM t LIMIT 10 OFFSET 20', $query);
17+
18+
$query = 'SELECT 1 FROM t';
19+
$driver->applyLimit($query, 0, 20);
20+
Assert::same('SELECT 1 FROM t LIMIT 0 OFFSET 20', $query);
21+
22+
$query = 'SELECT 1 FROM t';
23+
$driver->applyLimit($query, 10, 0);
24+
Assert::same('SELECT 1 FROM t LIMIT 10', $query);
25+
26+
$query = 'SELECT 1 FROM t';
27+
$driver->applyLimit($query, NULL, 20);
28+
Assert::same('SELECT 1 FROM t LIMIT 18446744073709551615 OFFSET 20', $query);
29+
30+
$query = 'SELECT 1 FROM t';
31+
$driver->applyLimit($query, 10, NULL);
32+
Assert::same('SELECT 1 FROM t LIMIT 10', $query);
33+
34+
$query = 'SELECT 1 FROM t';
35+
$driver->applyLimit($query, -1, NULL);
36+
Assert::same('SELECT 1 FROM t LIMIT -1', $query);
37+
38+
$query = 'SELECT 1 FROM t';
39+
$driver->applyLimit($query, NULL, -1);
40+
Assert::same('SELECT 1 FROM t', $query);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use Tester\Assert;
4+
5+
require __DIR__ . '/../../bootstrap.php';
6+
7+
8+
$driver = new Nette\Database\Drivers\OciDriver(new Nette\Database\Connection('', '', '', ['lazy' => TRUE]), []);
9+
10+
$query = 'SELECT 1 FROM t';
11+
$driver->applyLimit($query, 10, 20);
12+
Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 30) WHERE "__rnum" > 20', $query);
13+
14+
$query = 'SELECT 1 FROM t';
15+
$driver->applyLimit($query, 0, 20);
16+
Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t WHERE ROWNUM <= 20) WHERE "__rnum" > 20', $query);
17+
18+
$query = 'SELECT 1 FROM t';
19+
$driver->applyLimit($query, 10, 0);
20+
Assert::same('SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10', $query);
21+
22+
$query = 'SELECT 1 FROM t';
23+
$driver->applyLimit($query, NULL, 20);
24+
Assert::same('SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (SELECT 1 FROM t) t ) WHERE "__rnum" > 20', $query);
25+
26+
$query = 'SELECT 1 FROM t';
27+
$driver->applyLimit($query, 10, NULL);
28+
Assert::same('SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= 10', $query);
29+
30+
$query = 'SELECT 1 FROM t';
31+
$driver->applyLimit($query, -1, NULL);
32+
Assert::same('SELECT * FROM (SELECT 1 FROM t) WHERE ROWNUM <= -1', $query);
33+
34+
$query = 'SELECT 1 FROM t';
35+
$driver->applyLimit($query, NULL, -1);
36+
Assert::same('SELECT 1 FROM t', $query);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
use Tester\Assert;
4+
5+
require __DIR__ . '/../../bootstrap.php';
6+
7+
8+
$driver = new Nette\Database\Drivers\OdbcDriver;
9+
10+
Assert::exception(function () use ($driver) {
11+
$query = 'SELECT 1 FROM t';
12+
$driver->applyLimit($query, 10, 20);
13+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
14+
15+
Assert::exception(function () use ($driver) {
16+
$query = 'SELECT 1 FROM t';
17+
$driver->applyLimit($query, 0, 20);
18+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
19+
20+
$query = 'SELECT 1 FROM t';
21+
$driver->applyLimit($query, 10, 0);
22+
Assert::same('SELECT TOP 10 1 FROM t', $query);
23+
24+
Assert::exception(function () use ($driver) {
25+
$query = 'SELECT 1 FROM t';
26+
$driver->applyLimit($query, NULL, 20);
27+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
28+
29+
$query = 'SELECT 1 FROM t';
30+
$driver->applyLimit($query, 10, NULL);
31+
Assert::same('SELECT TOP 10 1 FROM t', $query);
32+
33+
$query = ' select distinct 1 FROM t';
34+
$driver->applyLimit($query, 10, NULL);
35+
Assert::same(' select distinct TOP 10 1 FROM t', $query);
36+
37+
$query = 'UPDATE t SET';
38+
$driver->applyLimit($query, 10, NULL);
39+
Assert::same('UPDATE TOP 10 t SET', $query);
40+
41+
$query = 'DELETE FROM t SET';
42+
$driver->applyLimit($query, 10, NULL);
43+
Assert::same('DELETE TOP 10 FROM t SET', $query);
44+
45+
Assert::exception(function () use ($driver) {
46+
$query = 'SET FROM t';
47+
$driver->applyLimit($query, 10, NULL);
48+
}, Nette\InvalidArgumentException::class, 'SQL query must begin with SELECT, UPDATE or DELETE command.');
49+
50+
$query = 'SELECT 1 FROM t';
51+
$driver->applyLimit($query, -1, NULL);
52+
Assert::same('SELECT TOP -1 1 FROM t', $query);
53+
54+
Assert::exception(function () use ($driver) {
55+
$query = 'SELECT 1 FROM t';
56+
$driver->applyLimit($query, NULL, -1);
57+
}, Nette\NotSupportedException::class, 'Offset is not supported by this database.');
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use Tester\Assert;
4+
5+
require __DIR__ . '/../../bootstrap.php';
6+
7+
8+
$driver = new Nette\Database\Drivers\PgSqlDriver(new Nette\Database\Connection('', '', '', ['lazy' => TRUE]), []);
9+
10+
$query = 'SELECT 1 FROM t';
11+
$driver->applyLimit($query, 10, 20);
12+
Assert::same('SELECT 1 FROM t LIMIT 10 OFFSET 20', $query);
13+
14+
$query = 'SELECT 1 FROM t';
15+
$driver->applyLimit($query, 0, 20);
16+
Assert::same('SELECT 1 FROM t LIMIT 0 OFFSET 20', $query);
17+
18+
$query = 'SELECT 1 FROM t';
19+
$driver->applyLimit($query, 10, 0);
20+
Assert::same('SELECT 1 FROM t LIMIT 10', $query);
21+
22+
$query = 'SELECT 1 FROM t';
23+
$driver->applyLimit($query, NULL, 20);
24+
Assert::same('SELECT 1 FROM t OFFSET 20', $query);
25+
26+
$query = 'SELECT 1 FROM t';
27+
$driver->applyLimit($query, 10, NULL);
28+
Assert::same('SELECT 1 FROM t LIMIT 10', $query);
29+
30+
$query = 'SELECT 1 FROM t';
31+
$driver->applyLimit($query, -1, NULL);
32+
Assert::same('SELECT 1 FROM t LIMIT -1', $query);
33+
34+
$query = 'SELECT 1 FROM t';
35+
$driver->applyLimit($query, NULL, -1);
36+
Assert::same('SELECT 1 FROM t', $query);

tests/Database/PgSqlDriver.formatLike.phpt renamed to tests/Database/Drivers/PgSqlDriver.formatLike.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<?php
22

33
/**
4-
* @dataProvider? databases.ini postgresql
4+
* @dataProvider? ../databases.ini postgresql
55
*/
66

77
use Tester\Assert;
88

9-
require __DIR__ . '/connect.inc.php'; // create $connection
9+
require __DIR__ . '/../connect.inc.php'; // create $connection
1010

1111

1212
$tests = function ($connection) {

0 commit comments

Comments
 (0)