From fd5cfaa9d320ae155c7eb10653df4926faf50be0 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 26 Oct 2015 17:51:52 +0100 Subject: [PATCH] drivers: applyLimit throws exception for negative values (BC break) --- src/Dibi/Drivers/MsSqlDriver.php | 13 ++++----- src/Dibi/Drivers/MySqlDriver.php | 9 ++++--- src/Dibi/Drivers/MySqliDriver.php | 9 ++++--- src/Dibi/Drivers/OdbcDriver.php | 13 ++++----- src/Dibi/Drivers/OracleDriver.php | 9 ++++--- src/Dibi/Drivers/PdoDriver.php | 42 +++++++++++++++++++----------- src/Dibi/Drivers/PostgreDriver.php | 8 +++--- src/Dibi/Drivers/Sqlite3Driver.php | 8 ++++-- src/Dibi/Drivers/SqlsrvDriver.php | 5 +++- src/Dibi/Translator.php | 6 ++--- 10 files changed, 77 insertions(+), 45 deletions(-) diff --git a/src/Dibi/Drivers/MsSqlDriver.php b/src/Dibi/Drivers/MsSqlDriver.php index 59c541e2..cd600efd 100644 --- a/src/Dibi/Drivers/MsSqlDriver.php +++ b/src/Dibi/Drivers/MsSqlDriver.php @@ -283,13 +283,14 @@ class MsSqlDriver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - // offset support is missing - if ($limit >= 0) { - $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t'; - } - if ($offset) { - throw new Dibi\NotImplementedException('Offset is not implemented.'); + throw new Dibi\NotSupportedException('Offset is not supported by this database.'); + + } elseif ($limit < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== NULL) { + $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t'; } } diff --git a/src/Dibi/Drivers/MySqlDriver.php b/src/Dibi/Drivers/MySqlDriver.php index d8b235f3..60b79537 100644 --- a/src/Dibi/Drivers/MySqlDriver.php +++ b/src/Dibi/Drivers/MySqlDriver.php @@ -368,10 +368,13 @@ class MySqlDriver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - if ($limit >= 0 || $offset > 0) { + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== NULL || $offset) { // see http://dev.mysql.com/doc/refman/5.0/en/select.html - $sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit) - . ($offset > 0 ? ' OFFSET ' . (int) $offset : ''); + $sql .= ' LIMIT ' . ($limit === NULL ? '18446744073709551615' : (int) $limit) + . ($offset ? ' OFFSET ' . (int) $offset : ''); } } diff --git a/src/Dibi/Drivers/MySqliDriver.php b/src/Dibi/Drivers/MySqliDriver.php index b3e1f4b5..71f1a3de 100644 --- a/src/Dibi/Drivers/MySqliDriver.php +++ b/src/Dibi/Drivers/MySqliDriver.php @@ -379,10 +379,13 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - if ($limit >= 0 || $offset > 0) { + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== NULL || $offset) { // see http://dev.mysql.com/doc/refman/5.0/en/select.html - $sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit) - . ($offset > 0 ? ' OFFSET ' . (int) $offset : ''); + $sql .= ' LIMIT ' . ($limit === NULL ? '18446744073709551615' : (int) $limit) + . ($offset ? ' OFFSET ' . (int) $offset : ''); } } diff --git a/src/Dibi/Drivers/OdbcDriver.php b/src/Dibi/Drivers/OdbcDriver.php index eba789a6..bb82dd82 100644 --- a/src/Dibi/Drivers/OdbcDriver.php +++ b/src/Dibi/Drivers/OdbcDriver.php @@ -307,13 +307,14 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector */ public function applyLimit(& $sql, $limit, $offset) { - // offset support is missing - if ($limit >= 0) { - $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t'; - } - if ($offset) { - throw new Dibi\NotSupportedException('Offset is not implemented in driver odbc.'); + throw new Dibi\NotSupportedException('Offset is not supported by this database.'); + + } elseif ($limit < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== NULL) { + $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t'; } } diff --git a/src/Dibi/Drivers/OracleDriver.php b/src/Dibi/Drivers/OracleDriver.php index 6e4bef24..24a25ddb 100644 --- a/src/Dibi/Drivers/OracleDriver.php +++ b/src/Dibi/Drivers/OracleDriver.php @@ -327,13 +327,16 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector */ public function applyLimit(& $sql, $limit, $offset) { - if ($offset > 0) { + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($offset) { // see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html $sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t ' - . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') + . ($limit !== NULL ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') . ') WHERE "__rnum" > '. (int) $offset; - } elseif ($limit >= 0) { + } elseif ($limit !== NULL) { $sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit; } } diff --git a/src/Dibi/Drivers/PdoDriver.php b/src/Dibi/Drivers/PdoDriver.php index ab74c351..ca9368ae 100644 --- a/src/Dibi/Drivers/PdoDriver.php +++ b/src/Dibi/Drivers/PdoDriver.php @@ -397,35 +397,43 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - if ($limit < 0 && $offset < 1) { - return; + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); } switch ($this->driverName) { case 'mysql': - $sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit) - . ($offset > 0 ? ' OFFSET ' . (int) $offset : ''); + if ($limit !== NULL || $offset) { + // see http://dev.mysql.com/doc/refman/5.0/en/select.html + $sql .= ' LIMIT ' . ($limit === NULL ? '18446744073709551615' : (int) $limit) + . ($offset ? ' OFFSET ' . (int) $offset : ''); + } break; case 'pgsql': - if ($limit >= 0) { + if ($limit !== NULL) { $sql .= ' LIMIT ' . (int) $limit; } - if ($offset > 0) { + if ($offset) { $sql .= ' OFFSET ' . (int) $offset; } break; case 'sqlite': - $sql .= ' LIMIT ' . $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : ''); + if ($limit !== NULL || $offset) { + $sql .= ' LIMIT ' . ($limit === NULL ? '-1' : (int) $limit) + . ($offset ? ' OFFSET ' . (int) $offset : ''); + } break; case 'oci': - if ($offset > 0) { + if ($offset) { + // see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html $sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t ' - . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') + . ($limit !== NULL ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '') . ') WHERE "__rnum" > '. (int) $offset; - } elseif ($limit >= 0) { + + } elseif ($limit !== NULL) { $sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit; } break; @@ -433,17 +441,21 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver case 'mssql': case 'sqlsrv': case 'dblib': - if (version_compare($this->serverVersion, '11.0') >= 0) { - if ($offset >= 0 || $limit >= 0) { - $sql .= ' OFFSET ' . (int) $offset . ' ROWS' - . ($limit > 0 ? ' FETCH NEXT ' . (int) $limit . ' ROWS ONLY' : ''); + if (version_compare($this->serverVersion, '11.0') >= 0) { // 11 == SQL Server 2012 + if ($limit !== NULL || $offset) { + // requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx + $sql .= ' OFFSET ' . (int) $offset . ' ROWS ' + . 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY'; } break; } // intentionally break omitted case 'odbc': - if ($offset < 1) { + if ($offset) { + throw new Dibi\NotSupportedException('Offset is not supported by this database.'); + + } elseif ($limit !== NULL) { $sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t'; break; } diff --git a/src/Dibi/Drivers/PostgreDriver.php b/src/Dibi/Drivers/PostgreDriver.php index 84d5663f..d75aa628 100644 --- a/src/Dibi/Drivers/PostgreDriver.php +++ b/src/Dibi/Drivers/PostgreDriver.php @@ -383,11 +383,13 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector */ public function applyLimit(& $sql, $limit, $offset) { - if ($limit >= 0) { + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + } + if ($limit !== NULL) { $sql .= ' LIMIT ' . (int) $limit; } - - if ($offset > 0) { + if ($offset) { $sql .= ' OFFSET ' . (int) $offset; } } diff --git a/src/Dibi/Drivers/Sqlite3Driver.php b/src/Dibi/Drivers/Sqlite3Driver.php index 9256df5b..d723ecf5 100644 --- a/src/Dibi/Drivers/Sqlite3Driver.php +++ b/src/Dibi/Drivers/Sqlite3Driver.php @@ -327,8 +327,12 @@ class Sqlite3Driver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - if ($limit >= 0 || $offset > 0) { - $sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : ''); + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif ($limit !== NULL || $offset) { + $sql .= ' LIMIT ' . ($limit === NULL ? '-1' : (int) $limit) + . ($offset ? ' OFFSET ' . (int) $offset : ''); } } diff --git a/src/Dibi/Drivers/SqlsrvDriver.php b/src/Dibi/Drivers/SqlsrvDriver.php index f58b035d..db2ebced 100644 --- a/src/Dibi/Drivers/SqlsrvDriver.php +++ b/src/Dibi/Drivers/SqlsrvDriver.php @@ -301,7 +301,10 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver */ public function applyLimit(& $sql, $limit, $offset) { - if (version_compare($this->version, 11, '<')) { // 11 == SQL Server 2012 + if ($limit < 0 || $offset < 0) { + throw new Dibi\NotSupportedException('Negative offset or limit.'); + + } elseif (version_compare($this->version, 11, '<')) { // 11 == SQL Server 2012 if ($offset) { throw new Dibi\NotSupportedException('Offset is not supported by this database.'); diff --git a/src/Dibi/Translator.php b/src/Dibi/Translator.php index e4137bde..b425dd94 100644 --- a/src/Dibi/Translator.php +++ b/src/Dibi/Translator.php @@ -74,8 +74,8 @@ final class Translator } $this->args = $args; - $this->limit = -1; - $this->offset = 0; + $this->limit = NULL; + $this->offset = NULL; $this->hasError = FALSE; $commandIns = NULL; $lastArr = NULL; @@ -171,7 +171,7 @@ final class Translator } // apply limit - if ($this->limit > -1 || $this->offset > 0) { + if ($this->limit !== NULL || $this->offset !== NULL) { $this->driver->applyLimit($sql, $this->limit, $this->offset); }