diff --git a/src/Dibi/DataSource.php b/src/Dibi/DataSource.php index bcfc7caf..7951de8e 100644 --- a/src/Dibi/DataSource.php +++ b/src/Dibi/DataSource.php @@ -260,9 +260,9 @@ FROM %SQL', $this->sql, ' { if ($this->count === null) { $this->count = $this->conds || $this->offset || $this->limit - ? (int) $this->connection->nativeQuery( + ? Helpers::intVal($this->connection->nativeQuery( 'SELECT COUNT(*) FROM (' . $this->__toString() . ') t' - )->fetchSingle() + )->fetchSingle()) : $this->getTotalCount(); } return $this->count; @@ -275,9 +275,9 @@ FROM %SQL', $this->sql, ' public function getTotalCount(): int { if ($this->totalCount === null) { - $this->totalCount = (int) $this->connection->nativeQuery( + $this->totalCount = Helpers::intVal($this->connection->nativeQuery( 'SELECT COUNT(*) FROM ' . $this->sql - )->fetchSingle(); + )->fetchSingle()); } return $this->totalCount; } diff --git a/src/Dibi/Drivers/MsSqlReflector.php b/src/Dibi/Drivers/MsSqlReflector.php index 5d819da9..a04964b5 100644 --- a/src/Dibi/Drivers/MsSqlReflector.php +++ b/src/Dibi/Drivers/MsSqlReflector.php @@ -68,12 +68,12 @@ class MsSqlReflector implements Dibi\Reflector if (!is_array($row) || count($row) < 1) { if ($fallback) { $row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escapeIdentifier($table)}")->fetch(false); - $count = (int) ($row[0]); + $count = Dibi\Helpers::intVal($row[0]); } else { $count = null; } } else { - $count = (int) ($row[0]); + $count = Dibi\Helpers::intVal($row[0]); } return $count; diff --git a/src/Dibi/Drivers/OracleDriver.php b/src/Dibi/Drivers/OracleDriver.php index 8eb26647..8b3d5a0d 100644 --- a/src/Dibi/Drivers/OracleDriver.php +++ b/src/Dibi/Drivers/OracleDriver.php @@ -159,7 +159,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector public function getInsertId(?string $sequence): ?int { $row = $this->query("SELECT $sequence.CURRVAL AS ID FROM DUAL")->fetch(true); - return isset($row['ID']) ? (int) $row['ID'] : null; + return isset($row['ID']) ? Dibi\Helpers::intVal($row['ID']) : null; } diff --git a/src/Dibi/Drivers/SqlsrvDriver.php b/src/Dibi/Drivers/SqlsrvDriver.php index d30f81d3..23f6ad08 100644 --- a/src/Dibi/Drivers/SqlsrvDriver.php +++ b/src/Dibi/Drivers/SqlsrvDriver.php @@ -139,7 +139,7 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver $res = sqlsrv_query($this->connection, 'SELECT SCOPE_IDENTITY()'); if (is_resource($res)) { $row = sqlsrv_fetch_array($res, SQLSRV_FETCH_NUMERIC); - return (int) $row[0]; + return Dibi\Helpers::intVal($row[0]); } return null; } diff --git a/src/Dibi/Fluent.php b/src/Dibi/Fluent.php index 52c78145..f05db1be 100644 --- a/src/Dibi/Fluent.php +++ b/src/Dibi/Fluent.php @@ -378,9 +378,9 @@ class Fluent implements IDataSource public function count(): int { - return (int) $this->query([ + return Helpers::intVal($this->query([ 'SELECT COUNT(*) FROM (%ex', $this->_export(), ') [data]', - ])->fetchSingle(); + ])->fetchSingle()); } diff --git a/src/Dibi/Helpers.php b/src/Dibi/Helpers.php index 67774c1c..e13dcaef 100644 --- a/src/Dibi/Helpers.php +++ b/src/Dibi/Helpers.php @@ -285,4 +285,23 @@ class Helpers { return $val === false ? null : $val; } + + + /** + * @internal + * @return string|int + */ + public static function intVal($value): int + { + if (is_int($value)) { + return $value; + } elseif (is_string($value) && preg_match('#-?\d++\z#A', $value)) { + if (is_float($value * 1)) { + throw new Exception("Number $value is greater than integer."); + } + return (int) $value; + } else { + throw new Exception("Expected number, '$value' given."); + } + } } diff --git a/src/Dibi/Translator.php b/src/Dibi/Translator.php index e9566426..00dcb9a1 100644 --- a/src/Dibi/Translator.php +++ b/src/Dibi/Translator.php @@ -536,7 +536,7 @@ final class Translator } elseif ($this->comment) { return "(limit $arg)"; } else { - $this->limit = (int) $arg; + $this->limit = Helpers::intVal($arg); } return ''; @@ -546,7 +546,7 @@ final class Translator } elseif ($this->comment) { return "(offset $arg)"; } else { - $this->offset = (int) $arg; + $this->offset = Helpers::intVal($arg); } return ''; diff --git a/tests/dibi/Fluent.select.phpt b/tests/dibi/Fluent.select.phpt index 78f24bd8..723cc2cb 100644 --- a/tests/dibi/Fluent.select.phpt +++ b/tests/dibi/Fluent.select.phpt @@ -144,10 +144,9 @@ if ($config['system'] === 'mysql') { ->limit(' 1; DROP TABLE users') ->offset(' 1; DROP TABLE users'); - Assert::same( - reformat(' SELECT * LIMIT 1 OFFSET 1'), - (string) $fluent - ); + Assert::error(function () use ($fluent) { + (string) $fluent; + }, E_USER_ERROR, "Expected number, ' 1; DROP TABLE users' given."); } diff --git a/tests/dibi/Helpers.intVal().phpt b/tests/dibi/Helpers.intVal().phpt new file mode 100644 index 00000000..d9498f88 --- /dev/null +++ b/tests/dibi/Helpers.intVal().phpt @@ -0,0 +1,32 @@ +