1
0
mirror of https://github.com/dg/dibi.git synced 2025-09-03 19:12:33 +02:00

Compare commits

...

15 Commits

Author SHA1 Message Date
David Grudl
32b6976209 removed support for SQLServer < 2012, PostgreSQL < 9.3 2025-08-07 00:26:19 +02:00
David Grudl
f484630e56 readonly properties 2025-08-07 00:26:19 +02:00
David Grudl
611e051c02 optimized global function calls 2025-08-07 00:26:19 +02:00
David Grudl
7595a6d5bd composer: added psr-4 loader 2025-08-07 00:25:10 +02:00
David Grudl
494d7c1c21 composer: require stable packages outside of nette 2025-08-07 00:25:10 +02:00
David Grudl
658dbe388a support for PHP 8.5 2025-08-07 00:10:17 +02:00
David Grudl
c7fe0fef21 uses PHP 8.2 features 2025-08-07 00:10:17 +02:00
David Grudl
9151d1eb9c requires PHP 8.2 2025-08-07 00:08:29 +02:00
David Grudl
d76f40c2a4 opened 5.1-dev 2025-08-07 00:04:06 +02:00
David Grudl
befde664fe tests: improved descriptions 2025-08-07 00:00:40 +02:00
David Grudl
e1c4cbaece exception: use natural explanatory style 2025-08-07 00:00:40 +02:00
David Grudl
1df20ced10 cs 2025-08-07 00:00:40 +02:00
David Grudl
ce1ba4668b uses promoted properties 2025-08-07 00:00:40 +02:00
David Grudl
0f21a6ab3d removed dead code 2025-08-07 00:00:40 +02:00
David Grudl
78f552fe8e github actions updated 2025-08-07 00:00:40 +02:00
61 changed files with 298 additions and 409 deletions

View File

@@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2 - uses: shivammathur/setup-php@v2
with: with:
php-version: 8.0 php-version: 8.3
coverage: none coverage: none
- run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress
@@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2 - uses: shivammathur/setup-php@v2
with: with:
php-version: 8.0 php-version: 8.3
coverage: none coverage: none
- run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress - run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress

View File

@@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2 - uses: shivammathur/setup-php@v2
with: with:
php-version: 8.0 php-version: 8.2
coverage: none coverage: none
- run: composer install --no-progress --prefer-dist - run: composer install --no-progress --prefer-dist

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
php: ['8.0', '8.1', '8.2', '8.3', '8.4'] php: ['8.2', '8.3', '8.4', '8.5']
fail-fast: false fail-fast: false
@@ -105,14 +105,14 @@ jobs:
- run: composer install --no-progress --prefer-dist - run: composer install --no-progress --prefer-dist
- run: vendor/bin/tester -p phpdbg tests -s -C --coverage ./coverage.xml --coverage-src ./src - run: vendor/bin/tester -p phpdbg tests -s -C --coverage ./coverage.xml --coverage-src ./src
- if: failure() - if: failure()
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: output name: output-${{ matrix.php }}
path: tests/**/output path: tests/**/output
- name: Save Code Coverage - name: Save Code Coverage
if: ${{ matrix.php == '8.0' }} if: ${{ matrix.php == '8.2' }}
env: env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |

View File

@@ -11,20 +11,23 @@
} }
], ],
"require": { "require": {
"php": "8.0 - 8.4" "php": "8.2 - 8.5"
}, },
"require-dev": { "require-dev": {
"tracy/tracy": "^2.9", "tracy/tracy": "^2.9",
"nette/tester": "^2.5", "nette/tester": "^2.5",
"nette/di": "^3.1", "nette/di": "^3.1",
"phpstan/phpstan": "^1.0", "phpstan/phpstan-nette": "^2.0@stable",
"jetbrains/phpstorm-attributes": "^1.0" "jetbrains/phpstorm-attributes": "^1.0"
}, },
"replace": { "replace": {
"dg/dibi": "*" "dg/dibi": "*"
}, },
"autoload": { "autoload": {
"classmap": ["src/"] "classmap": ["src/"],
"psr-4": {
"Dibi\\": "src/Dibi"
}
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"scripts": { "scripts": {
@@ -33,7 +36,7 @@
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "5.0-dev" "dev-master": "5.1-dev"
} }
} }
} }

View File

@@ -45,7 +45,7 @@ function substFallBack($expr)
// define callback // define callback
$dibi->getSubstitutes()->setCallback('substFallBack'); $dibi->getSubstitutes()->setCallback(substFallBack(...));
// define substitutes as constants // define substitutes as constants
define('SUBST_ACCOUNT', 'eshop_'); define('SUBST_ACCOUNT', 'eshop_');

View File

@@ -34,7 +34,7 @@ Install Dibi via Composer:
composer require dibi/dibi composer require dibi/dibi
``` ```
The Dibi 5.0 requires PHP version 8.0 and supports PHP up to 8.4. The Dibi 5.1 requires PHP version 8.2 and supports PHP up to 8.5.
Usage Usage

View File

@@ -19,14 +19,10 @@ use Tracy;
*/ */
class DibiExtension22 extends Nette\DI\CompilerExtension class DibiExtension22 extends Nette\DI\CompilerExtension
{ {
private ?bool $debugMode; public function __construct(
private ?bool $cliMode; private ?bool $debugMode = null,
private ?bool $cliMode = null,
) {
public function __construct(?bool $debugMode = null, ?bool $cliMode = null)
{
$this->debugMode = $debugMode;
$this->cliMode = $cliMode;
} }

View File

@@ -13,6 +13,7 @@ use Dibi;
use Nette; use Nette;
use Nette\Schema\Expect; use Nette\Schema\Expect;
use Tracy; use Tracy;
use function is_array;
/** /**
@@ -20,14 +21,10 @@ use Tracy;
*/ */
class DibiExtension3 extends Nette\DI\CompilerExtension class DibiExtension3 extends Nette\DI\CompilerExtension
{ {
private ?bool $debugMode; public function __construct(
private ?bool $cliMode; private ?bool $debugMode = null,
private ?bool $cliMode = null,
) {
public function __construct(?bool $debugMode = null, ?bool $cliMode = null)
{
$this->debugMode = $debugMode;
$this->cliMode = $cliMode;
} }

View File

@@ -13,6 +13,7 @@ use Dibi;
use Dibi\Event; use Dibi\Event;
use Dibi\Helpers; use Dibi\Helpers;
use Tracy; use Tracy;
use function count, is_string, strlen;
/** /**
@@ -21,23 +22,22 @@ use Tracy;
class Panel implements Tracy\IBarPanel class Panel implements Tracy\IBarPanel
{ {
public static int $maxLength = 1000; public static int $maxLength = 1000;
public bool|string $explain;
public int $filter;
private array $events = []; private array $events = [];
public function __construct(bool $explain = true, ?int $filter = null) public function __construct(
{ public bool|string $explain = true,
$this->filter = $filter ?: Event::QUERY; public int $filter = Event::QUERY,
$this->explain = $explain; ) {
} }
public function register(Dibi\Connection $connection): void public function register(Dibi\Connection $connection): void
{ {
Tracy\Debugger::getBar()->addPanel($this); Tracy\Debugger::getBar()->addPanel($this);
Tracy\Debugger::getBlueScreen()->addPanel([self::class, 'renderException']); Tracy\Debugger::getBlueScreen()->addPanel(self::renderException(...));
$connection->onEvent[] = [$this, 'logEvent']; $connection->onEvent[] = $this->logEvent(...);
} }

View File

@@ -11,6 +11,8 @@ namespace Dibi;
use JetBrains\PhpStorm\Language; use JetBrains\PhpStorm\Language;
use Traversable; use Traversable;
use function array_key_exists, is_array, sprintf;
use const PHP_SAPI;
/** /**
@@ -673,7 +675,7 @@ class Connection implements IConnection
/** /**
* Prevents unserialization. * Prevents unserialization.
*/ */
public function __wakeup() public function __unserialize($_)
{ {
throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.'); throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.');
} }
@@ -682,7 +684,7 @@ class Connection implements IConnection
/** /**
* Prevents serialization. * Prevents serialization.
*/ */
public function __sleep() public function __serialize()
{ {
throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.'); throw new NotSupportedException('You cannot serialize or unserialize ' . static::class . ' instances.');
} }

View File

@@ -9,14 +9,16 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function func_get_args, is_array, strpbrk;
/** /**
* Default implementation of IDataSource. * Default implementation of IDataSource.
*/ */
class DataSource implements IDataSource class DataSource implements IDataSource
{ {
private Connection $connection; private readonly Connection $connection;
private string $sql; private readonly string $sql;
private ?Result $result = null; private ?Result $result = null;
private ?int $count = null; private ?int $count = null;
private ?int $totalCount = null; private ?int $totalCount = null;

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use function is_resource;
/** /**

View File

@@ -17,12 +17,9 @@ use Dibi;
*/ */
class FirebirdReflector implements Dibi\Reflector class FirebirdReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use function is_resource;
/** /**
@@ -18,16 +19,10 @@ use Dibi\Helpers;
*/ */
class FirebirdResult implements Dibi\ResultDriver class FirebirdResult implements Dibi\ResultDriver
{ {
/** @var resource */ public function __construct(
private $resultSet; /** @var resource */
private $resultSet,
) {
/**
* @param resource $resultSet
*/
public function __construct($resultSet)
{
$this->resultSet = $resultSet;
} }

View File

@@ -18,12 +18,9 @@ use Dibi;
*/ */
class MySqlReflector implements Dibi\Reflector class MySqlReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function in_array;
use const MYSQLI_REPORT_OFF, MYSQLI_STORE_RESULT, MYSQLI_USE_RESULT, PREG_SET_ORDER;
/** /**

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use const MYSQLI_TYPE_LONG, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_TIME, MYSQLI_TYPE_TINY;
/** /**
@@ -17,14 +18,10 @@ use Dibi;
*/ */
class MySqliResult implements Dibi\ResultDriver class MySqliResult implements Dibi\ResultDriver
{ {
private \mysqli_result $resultSet; public function __construct(
private bool $buffered; private readonly \mysqli_result $resultSet,
private readonly bool $buffered,
) {
public function __construct(\mysqli_result $resultSet, bool $buffered)
{
$this->resultSet = $resultSet;
$this->buffered = $buffered;
} }

View File

@@ -17,12 +17,9 @@ use Dibi;
*/ */
class NoDataResult implements Dibi\ResultDriver class NoDataResult implements Dibi\ResultDriver
{ {
private int $rows; public function __construct(
private readonly int $rows,
) {
public function __construct(int $rows)
{
$this->rows = $rows;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function is_resource;
/** /**

View File

@@ -17,12 +17,9 @@ use Dibi;
*/ */
class OdbcReflector implements Dibi\Reflector class OdbcReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function is_resource;
/** /**
@@ -17,17 +18,13 @@ use Dibi;
*/ */
class OdbcResult implements Dibi\ResultDriver class OdbcResult implements Dibi\ResultDriver
{ {
/** @var resource */
private $resultSet;
private int $row = 0; private int $row = 0;
/** public function __construct(
* @param resource $resultSet /** @var resource */
*/ private $resultSet,
public function __construct($resultSet) ) {
{
$this->resultSet = $resultSet;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function in_array, is_resource;
/** /**

View File

@@ -17,12 +17,9 @@ use Dibi;
*/ */
class OracleReflector implements Dibi\Reflector class OracleReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function is_resource;
/** /**
@@ -17,16 +18,10 @@ use Dibi;
*/ */
class OracleResult implements Dibi\ResultDriver class OracleResult implements Dibi\ResultDriver
{ {
/** @var resource */ public function __construct(
private $resultSet; /** @var resource */
private $resultSet,
) {
/**
* @param resource $resultSet
*/
public function __construct($resultSet)
{
$this->resultSet = $resultSet;
} }

View File

@@ -12,6 +12,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use PDO; use PDO;
use function sprintf;
/** /**
@@ -23,14 +24,12 @@ use PDO;
* - password (or pass) * - password (or pass)
* - options (array) => driver specific options {@see PDO::__construct} * - options (array) => driver specific options {@see PDO::__construct}
* - resource (PDO) => existing connection * - resource (PDO) => existing connection
* - version
*/ */
class PdoDriver implements Dibi\Driver class PdoDriver implements Dibi\Driver
{ {
private ?PDO $connection; private ?PDO $connection;
private ?int $affectedRows; private ?int $affectedRows;
private string $driverName; private string $driverName;
private string $serverVersion = '';
/** @throws Dibi\NotSupportedException */ /** @throws Dibi\NotSupportedException */
@@ -65,7 +64,6 @@ class PdoDriver implements Dibi\Driver
} }
$this->driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME); $this->driverName = $this->connection->getAttribute(PDO::ATTR_DRIVER_NAME);
$this->serverVersion = (string) ($config['version'] ?? @$this->connection->getAttribute(PDO::ATTR_SERVER_VERSION)); // @ - may be not supported
} }
@@ -179,7 +177,7 @@ class PdoDriver implements Dibi\Driver
return match ($this->driverName) { return match ($this->driverName) {
'mysql' => new MySqlReflector($this), 'mysql' => new MySqlReflector($this),
'oci' => new OracleReflector($this), 'oci' => new OracleReflector($this),
'pgsql' => new PostgreReflector($this, $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION)), 'pgsql' => new PostgreReflector($this),
'sqlite' => new SqliteReflector($this), 'sqlite' => new SqliteReflector($this),
'mssql', 'dblib', 'sqlsrv' => new SqlsrvReflector($this), 'mssql', 'dblib', 'sqlsrv' => new SqlsrvReflector($this),
default => throw new Dibi\NotSupportedException, default => throw new Dibi\NotSupportedException,
@@ -359,17 +357,15 @@ class PdoDriver implements Dibi\Driver
case 'mssql': case 'mssql':
case 'sqlsrv': case 'sqlsrv':
case 'dblib': case 'dblib':
if (version_compare($this->serverVersion, '11.0') >= 0) { // 11 == SQL Server 2012 // requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx if ($limit !== null) {
if ($limit !== null) { $sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit);
$sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit); } elseif ($offset) {
} elseif ($offset) { $sql = sprintf('%s OFFSET %d ROWS', rtrim($sql), $offset);
$sql = sprintf('%s OFFSET %d ROWS', rtrim($sql), $offset);
}
break;
} }
// break omitted
break;
case 'odbc': case 'odbc':
if ($offset) { if ($offset) {
throw new Dibi\NotSupportedException('Offset is not supported by this database.'); throw new Dibi\NotSupportedException('Offset is not supported by this database.');

View File

@@ -19,14 +19,10 @@ use PDO;
*/ */
class PdoResult implements Dibi\ResultDriver class PdoResult implements Dibi\ResultDriver
{ {
private ?\PDOStatement $resultSet; public function __construct(
private string $driverName; private ?\PDOStatement $resultSet,
private readonly string $driverName,
) {
public function __construct(\PDOStatement $resultSet, string $driverName)
{
$this->resultSet = $resultSet;
$this->driverName = $driverName;
} }

View File

@@ -12,6 +12,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use PgSql; use PgSql;
use function in_array, is_array, is_resource, strlen;
/** /**
@@ -23,13 +24,12 @@ use PgSql;
* - schema => the schema search path * - schema => the schema search path
* - charset => character encoding to set (default is utf8) * - charset => character encoding to set (default is utf8)
* - persistent (bool) => try to find a persistent link? * - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource * - resource (PgSql\Connection) => existing connection resource
* - connect_type (int) => see pg_connect() * - connect_type (int) => see pg_connect()
*/ */
class PostgreDriver implements Dibi\Driver class PostgreDriver implements Dibi\Driver
{ {
/** @var resource|PgSql\Connection */ private PgSql\Connection $connection;
private $connection;
private ?int $affectedRows; private ?int $affectedRows;
@@ -72,7 +72,7 @@ class PostgreDriver implements Dibi\Driver
restore_error_handler(); restore_error_handler();
} }
if (!is_resource($this->connection) && !$this->connection instanceof PgSql\Connection) { if (!$this->connection instanceof PgSql\Connection) {
throw new Dibi\DriverException($error ?: 'Connecting error.'); throw new Dibi\DriverException($error ?: 'Connecting error.');
} }
@@ -118,7 +118,7 @@ class PostgreDriver implements Dibi\Driver
if ($res === false) { if ($res === false) {
throw static::createException(pg_last_error($this->connection), null, $sql); throw static::createException(pg_last_error($this->connection), null, $sql);
} elseif (is_resource($res) || $res instanceof PgSql\Result) { } elseif ($res instanceof PgSql\Result) {
$this->affectedRows = Helpers::false2Null(pg_affected_rows($res)); $this->affectedRows = Helpers::false2Null(pg_affected_rows($res));
if (pg_num_fields($res)) { if (pg_num_fields($res)) {
return $this->createResultDriver($res); return $this->createResultDriver($res);
@@ -222,13 +222,10 @@ class PostgreDriver implements Dibi\Driver
/** /**
* Returns the connection resource. * Returns the connection resource.
* @return resource|null
*/ */
public function getResource(): mixed public function getResource(): PgSql\Connection
{ {
return is_resource($this->connection) || $this->connection instanceof PgSql\Connection return $this->connection;
? $this->connection
: null;
} }
@@ -237,15 +234,14 @@ class PostgreDriver implements Dibi\Driver
*/ */
public function getReflector(): Dibi\Reflector public function getReflector(): Dibi\Reflector
{ {
return new PostgreReflector($this, pg_parameter_status($this->connection, 'server_version')); return new PostgreReflector($this);
} }
/** /**
* Result set driver factory. * Result set driver factory.
* @param resource $resource
*/ */
public function createResultDriver($resource): PostgreResult public function createResultDriver(PgSql\Result $resource): PostgreResult
{ {
return new PostgreResult($resource); return new PostgreResult($resource);
} }

View File

@@ -17,14 +17,9 @@ use Dibi;
*/ */
class PostgreReflector implements Dibi\Reflector class PostgreReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private string $version; private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver, string $version)
{
$this->driver = $driver;
$this->version = $version;
} }
@@ -43,18 +38,15 @@ class PostgreReflector implements Dibi\Reflector
FROM FROM
information_schema.tables information_schema.tables
WHERE WHERE
table_schema = ANY (current_schemas(false))"; table_schema = ANY (current_schemas(false))
if ($this->version >= 9.3) { UNION ALL
$query .= ' SELECT
UNION ALL matviewname, 1
SELECT FROM
matviewname, 1 pg_matviews
FROM WHERE
pg_matviews schemaname = ANY (current_schemas(false))";
WHERE
schemaname = ANY (current_schemas(false))';
}
$res = $this->driver->query($query); $res = $this->driver->query($query);
$tables = []; $tables = [];

View File

@@ -19,16 +19,9 @@ use PgSql;
*/ */
class PostgreResult implements Dibi\ResultDriver class PostgreResult implements Dibi\ResultDriver
{ {
/** @var resource|PgSql\Result */ public function __construct(
private $resultSet; private readonly PgSql\Result $resultSet,
) {
/**
* @param resource|PgSql\Result $resultSet
*/
public function __construct($resultSet)
{
$this->resultSet = $resultSet;
} }
@@ -94,13 +87,10 @@ class PostgreResult implements Dibi\ResultDriver
/** /**
* Returns the result set resource. * Returns the result set resource.
* @return resource|PgSql\Result|null
*/ */
public function getResultResource(): mixed public function getResultResource(): PgSql\Result
{ {
return is_resource($this->resultSet) || $this->resultSet instanceof PgSql\Result return $this->resultSet;
? $this->resultSet
: null;
} }

View File

@@ -56,10 +56,7 @@ class SqliteDriver implements Dibi\Driver
} }
// enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced) // enable foreign keys support (defaultly disabled; if disabled then foreign key constraints are not enforced)
$version = SQLite3::version(); $this->query('PRAGMA foreign_keys = ON');
if ($version['versionNumber'] >= '3006019') {
$this->query('PRAGMA foreign_keys = ON');
}
} }

View File

@@ -17,12 +17,9 @@ use Dibi;
*/ */
class SqliteReflector implements Dibi\Reflector class SqliteReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use const SQLITE3_ASSOC, SQLITE3_BLOB, SQLITE3_FLOAT, SQLITE3_INTEGER, SQLITE3_NULL, SQLITE3_NUM, SQLITE3_TEXT;
/** /**
@@ -18,12 +19,9 @@ use Dibi\Helpers;
*/ */
class SqliteResult implements Dibi\ResultDriver class SqliteResult implements Dibi\ResultDriver
{ {
private \SQLite3Result $resultSet; public function __construct(
private readonly \SQLite3Result $resultSet,
) {
public function __construct(\SQLite3Result $resultSet)
{
$this->resultSet = $resultSet;
} }

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi; use Dibi;
use Dibi\Helpers; use Dibi\Helpers;
use function is_resource, sprintf;
/** /**
@@ -30,7 +31,6 @@ class SqlsrvDriver implements Dibi\Driver
/** @var resource */ /** @var resource */
private $connection; private $connection;
private ?int $affectedRows; private ?int $affectedRows;
private string $version = '';
/** @throws Dibi\NotSupportedException */ /** @throws Dibi\NotSupportedException */
@@ -68,8 +68,6 @@ class SqlsrvDriver implements Dibi\Driver
sqlsrv_configure('WarningsReturnAsErrors', 1); sqlsrv_configure('WarningsReturnAsErrors', 1);
} }
$this->version = sqlsrv_server_info($this->connection)['SQLServerVersion'];
} }
@@ -256,13 +254,6 @@ class SqlsrvDriver implements Dibi\Driver
if ($limit < 0 || $offset < 0) { if ($limit < 0 || $offset < 0) {
throw new Dibi\NotSupportedException('Negative offset or limit.'); 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.');
} elseif ($limit !== null) {
$sql = sprintf('SELECT TOP (%d) * FROM (%s) t', $limit, $sql);
}
} elseif ($limit !== null) { } elseif ($limit !== null) {
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx // requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
$sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit); $sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit);

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function sprintf;
/** /**
@@ -17,12 +18,9 @@ use Dibi;
*/ */
class SqlsrvReflector implements Dibi\Reflector class SqlsrvReflector implements Dibi\Reflector
{ {
private Dibi\Driver $driver; public function __construct(
private readonly Dibi\Driver $driver,
) {
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Drivers; namespace Dibi\Drivers;
use Dibi; use Dibi;
use function is_resource;
/** /**
@@ -17,16 +18,10 @@ use Dibi;
*/ */
class SqlsrvResult implements Dibi\ResultDriver class SqlsrvResult implements Dibi\ResultDriver
{ {
/** @var resource */ public function __construct(
private $resultSet; /** @var resource */
private $resultSet,
) {
/**
* @param resource $resultSet
*/
public function __construct($resultSet)
{
$this->resultSet = $resultSet;
} }

View File

@@ -9,6 +9,9 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function count, dirname, microtime, preg_match, str_starts_with, strtoupper, trim;
use const DIRECTORY_SEPARATOR;
/** /**
* Profiler & logger event. * Profiler & logger event.
@@ -29,10 +32,10 @@ class Event
TRANSACTION = 448, // BEGIN | COMMIT | ROLLBACK TRANSACTION = 448, // BEGIN | COMMIT | ROLLBACK
ALL = 1023; ALL = 1023;
public Connection $connection; public readonly Connection $connection;
public int $type; public int $type;
public string $sql; public readonly string $sql;
public Result|DriverException|null $result; public readonly Result|DriverException|null $result;
public float $time; public float $time;
public ?int $count = null; public ?int $count = null;
public ?array $source = null; public ?array $source = null;

View File

@@ -15,7 +15,7 @@ namespace Dibi;
*/ */
class Expression class Expression
{ {
private array $values; private readonly array $values;
public function __construct(...$values) public function __construct(...$values)

View File

@@ -9,6 +9,8 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function array_key_exists, count, func_get_args, is_array, is_string;
/** /**
* SQL builder via fluent interfaces. * SQL builder via fluent interfaces.
@@ -97,7 +99,7 @@ class Fluent implements IDataSource
'RIGHT JOIN' => 'FROM', 'RIGHT JOIN' => 'FROM',
]; ];
private Connection $connection; private readonly Connection $connection;
private array $setups = []; private array $setups = [];
private ?string $command = null; private ?string $command = null;
private array $clauses = []; private array $clauses = [];
@@ -113,7 +115,7 @@ class Fluent implements IDataSource
$this->connection = $connection; $this->connection = $connection;
if (!isset(self::$normalizer)) { if (!isset(self::$normalizer)) {
self::$normalizer = new HashMap([self::class, '_formatClause']); self::$normalizer = new HashMap(self::_formatClause(...));
} }
} }

View File

@@ -9,6 +9,9 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function array_map, array_unique, explode, fclose, fgets, fopen, fstat, getenv, htmlspecialchars, is_float, is_int, is_string, levenshtein, max, mb_strlen, ob_end_flush, ob_get_clean, ob_start, preg_match, preg_replace, preg_replace_callback, rtrim, set_time_limit, str_ends_with, str_repeat, str_starts_with, strlen, strtoupper, substr, trim, wordwrap;
use const PHP_SAPI;
class Helpers class Helpers
{ {
@@ -208,7 +211,7 @@ class Helpers
public static function getTypeCache(): HashMap public static function getTypeCache(): HashMap
{ {
if (!isset(self::$types)) { if (!isset(self::$types)) {
self::$types = new HashMap([self::class, 'detectType']); self::$types = new HashMap(self::detectType(...));
} }
return self::$types; return self::$types;

View File

@@ -15,7 +15,7 @@ namespace Dibi;
*/ */
class Literal class Literal
{ {
private string $value; private readonly string $value;
public function __construct($value) public function __construct($value)

View File

@@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Dibi\Loggers; namespace Dibi\Loggers;
use Dibi; use Dibi;
use function sprintf;
use const FILE_APPEND, LOCK_EX;
/** /**
@@ -17,17 +19,11 @@ use Dibi;
*/ */
class FileLogger class FileLogger
{ {
/** Name of the file where SQL errors should be logged */ public function __construct(
public string $file; public string $file,
public int $filter; public int $filter = Dibi\Event::QUERY,
private bool $errorsOnly; private bool $errorsOnly = false,
) {
public function __construct(string $file, ?int $filter = null, bool $errorsOnly = false)
{
$this->file = $file;
$this->filter = $filter ?: Dibi\Event::QUERY;
$this->errorsOnly = $errorsOnly;
} }

View File

@@ -27,17 +27,10 @@ use Dibi;
*/ */
class Column class Column
{ {
/** when created by Result */ public function __construct(
private ?Dibi\Reflector $reflector; private readonly ?Dibi\Reflector $reflector,
private array $info,
/** @var array (name, nativetype, [table], [fullname], [size], [nullable], [default], [autoincrement], [vendor]) */ ) {
private array $info;
public function __construct(?Dibi\Reflector $reflector, array $info)
{
$this->reflector = $reflector;
$this->info = $info;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Reflection; namespace Dibi\Reflection;
use Dibi; use Dibi;
use function array_values, strtolower;
/** /**
@@ -21,17 +22,14 @@ use Dibi;
*/ */
class Database class Database
{ {
private Dibi\Reflector $reflector;
private ?string $name;
/** @var Table[] */ /** @var Table[] */
private array $tables; private array $tables;
public function __construct(Dibi\Reflector $reflector, ?string $name = null) public function __construct(
{ private readonly Dibi\Reflector $reflector,
$this->reflector = $reflector; private ?string $name = null,
$this->name = $name; ) {
} }

View File

@@ -19,16 +19,10 @@ namespace Dibi\Reflection;
*/ */
class ForeignKey class ForeignKey
{ {
private string $name; public function __construct(
private readonly string $name,
/** @var array of [local, foreign, onDelete, onUpdate] */ private readonly array $references,
private array $references; ) {
public function __construct(string $name, array $references)
{
$this->name = $name;
$this->references = $references;
} }

View File

@@ -21,13 +21,9 @@ namespace Dibi\Reflection;
*/ */
class Index class Index
{ {
/** @var array (name, columns, [unique], [primary]) */ public function __construct(
private array $info; private readonly array $info,
) {
public function __construct(array $info)
{
$this->info = $info;
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Reflection; namespace Dibi\Reflection;
use Dibi; use Dibi;
use function array_values, strtolower;
/** /**
@@ -20,8 +21,6 @@ use Dibi;
*/ */
class Result class Result
{ {
private Dibi\ResultDriver $driver;
/** @var Column[]|null */ /** @var Column[]|null */
private ?array $columns; private ?array $columns;
@@ -29,9 +28,9 @@ class Result
private ?array $names; private ?array $names;
public function __construct(Dibi\ResultDriver $driver) public function __construct(
{ private readonly Dibi\ResultDriver $driver,
$this->driver = $driver; ) {
} }

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Dibi\Reflection; namespace Dibi\Reflection;
use Dibi; use Dibi;
use function array_values, strtolower;
/** /**
@@ -25,7 +26,7 @@ use Dibi;
*/ */
class Table class Table
{ {
private Dibi\Reflector $reflector; private readonly Dibi\Reflector $reflector;
private string $name; private string $name;
private bool $view; private bool $view;

View File

@@ -9,6 +9,9 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function array_keys, array_pop, count, explode, is_float, is_string, json_decode, ltrim, preg_match, preg_split, property_exists, reset, rtrim, str_contains, str_replace, str_starts_with, strpos;
use const PREG_SPLIT_DELIM_CAPTURE, PREG_SPLIT_NO_EMPTY;
/** /**
* Query result. * Query result.

View File

@@ -15,14 +15,13 @@ namespace Dibi;
*/ */
class ResultIterator implements \Iterator, \Countable class ResultIterator implements \Iterator, \Countable
{ {
private Result $result;
private mixed $row; private mixed $row;
private int $pointer = 0; private int $pointer = 0;
public function __construct(Result $result) public function __construct(
{ private readonly Result $result,
$this->result = $result; ) {
} }

View File

@@ -9,6 +9,8 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function array_keys, count, str_starts_with;
/** /**
* Result set single row. * Result set single row.

View File

@@ -9,14 +9,16 @@ declare(strict_types=1);
namespace Dibi; namespace Dibi;
use function array_filter, array_keys, array_splice, array_values, count, explode, get_debug_type, gettype, implode, is_array, is_bool, is_float, is_int, is_numeric, is_object, is_scalar, is_string, iterator_to_array, key, ltrim, number_format, preg_last_error, preg_match, preg_replace_callback, reset, rtrim, str_contains, str_replace, strcspn, strlen, strncasecmp, strtoupper, substr, trim;
/** /**
* SQL translator. * SQL translator.
*/ */
final class Translator final class Translator
{ {
private Connection $connection; private readonly Connection $connection;
private Driver $driver; private readonly Driver $driver;
private int $cursor = 0; private int $cursor = 0;
private array $args; private array $args;
@@ -34,7 +36,7 @@ final class Translator
{ {
$this->connection = $connection; $this->connection = $connection;
$this->driver = $connection->getDriver(); $this->driver = $connection->getDriver();
$this->identifiers = new HashMap([$this, 'delimite']); $this->identifiers = new HashMap($this->delimite(...));
} }
@@ -88,7 +90,7 @@ final class Translator
(\?) ## 11) placeholder (\?) ## 11) placeholder
)/xs )/xs
XX, XX,
[$this, 'cb'], $this->cb(...),
substr($arg, $toSkip), substr($arg, $toSkip),
); );
if (preg_last_error()) { if (preg_last_error()) {
@@ -434,7 +436,7 @@ final class Translator
:(\S*?:)([a-zA-Z0-9._]?) :(\S*?:)([a-zA-Z0-9._]?)
)/sx )/sx
XX, XX,
[$this, 'cb'], $this->cb(...),
substr($value, $toSkip), substr($value, $toSkip),
); );
if (preg_last_error()) { if (preg_last_error()) {

View File

@@ -37,7 +37,7 @@ declare(strict_types=1);
*/ */
class dibi class dibi
{ {
public const Version = '5.0.2'; public const Version = '5.1-dev';
/** @deprecated use dibi::Version */ /** @deprecated use dibi::Version */
public const VERSION = self::Version; public const VERSION = self::Version;

View File

@@ -11,7 +11,7 @@ namespace Dibi;
/** /**
* Dibi common exception. * A database operation failed.
*/ */
class Exception extends \Exception class Exception extends \Exception
{ {
@@ -44,7 +44,7 @@ class Exception extends \Exception
/** /**
* database server exception. * The database server reported an error.
*/ */
class DriverException extends Exception class DriverException extends Exception
{ {
@@ -52,7 +52,7 @@ class DriverException extends Exception
/** /**
* PCRE exception. * Regular expression pattern or execution failed.
*/ */
class PcreException extends Exception class PcreException extends Exception
{ {
@@ -63,18 +63,24 @@ class PcreException extends Exception
} }
/**
* The requested feature is not implemented.
*/
class NotImplementedException extends Exception class NotImplementedException extends Exception
{ {
} }
/**
* The requested operation is not supported.
*/
class NotSupportedException extends Exception class NotSupportedException extends Exception
{ {
} }
/** /**
* Database procedure exception. * A database stored procedure failed.
*/ */
class ProcedureException extends Exception class ProcedureException extends Exception
{ {
@@ -102,7 +108,7 @@ class ProcedureException extends Exception
/** /**
* Base class for all constraint violation related exceptions. * A database constraint was violated.
*/ */
class ConstraintViolationException extends DriverException class ConstraintViolationException extends DriverException
{ {
@@ -110,7 +116,7 @@ class ConstraintViolationException extends DriverException
/** /**
* Exception for a foreign key constraint violation. * The foreign key constraint check failed.
*/ */
class ForeignKeyConstraintViolationException extends ConstraintViolationException class ForeignKeyConstraintViolationException extends ConstraintViolationException
{ {
@@ -118,7 +124,7 @@ class ForeignKeyConstraintViolationException extends ConstraintViolationExceptio
/** /**
* Exception for a NOT NULL constraint violation. * The NOT NULL constraint check failed.
*/ */
class NotNullConstraintViolationException extends ConstraintViolationException class NotNullConstraintViolationException extends ConstraintViolationException
{ {
@@ -126,7 +132,7 @@ class NotNullConstraintViolationException extends ConstraintViolationException
/** /**
* Exception for a unique constraint violation. * The unique constraint check failed.
*/ */
class UniqueConstraintViolationException extends ConstraintViolationException class UniqueConstraintViolationException extends ConstraintViolationException
{ {

View File

@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/bootstrap.php'; require __DIR__ . '/bootstrap.php';
test('', function () use ($config) { test('immediate connection and disconnection state', function () use ($config) {
$conn = new Connection($config); $conn = new Connection($config);
Assert::true($conn->isConnected()); Assert::true($conn->isConnected());
@@ -21,7 +21,7 @@ test('', function () use ($config) {
}); });
test('lazy', function () use ($config) { test('lazy connection initiated on first query', function () use ($config) {
$conn = new Connection($config + ['lazy' => true]); $conn = new Connection($config + ['lazy' => true]);
Assert::false($conn->isConnected()); Assert::false($conn->isConnected());
@@ -30,7 +30,7 @@ test('lazy', function () use ($config) {
}); });
test('', function () use ($config) { test('config retrieval and driver instance access', function () use ($config) {
$conn = new Connection($config); $conn = new Connection($config);
Assert::true($conn->isConnected()); Assert::true($conn->isConnected());
@@ -40,7 +40,7 @@ test('', function () use ($config) {
}); });
test('', function () use ($config) { test('idempotent disconnect calls', function () use ($config) {
$conn = new Connection($config); $conn = new Connection($config);
Assert::true($conn->isConnected()); Assert::true($conn->isConnected());
@@ -52,7 +52,7 @@ test('', function () use ($config) {
}); });
test('', function () use ($config) { test('reconnect after disconnection', function () use ($config) {
$conn = new Connection($config); $conn = new Connection($config);
Assert::equal('hello', $conn->query('SELECT %s', 'hello')->fetchSingle()); Assert::equal('hello', $conn->query('SELECT %s', 'hello')->fetchSingle());
@@ -63,7 +63,7 @@ test('', function () use ($config) {
}); });
test('', function () use ($config) { test('destructor disconnects active connection', function () use ($config) {
$conn = new Connection($config); $conn = new Connection($config);
Assert::true($conn->isConnected()); Assert::true($conn->isConnected());
@@ -72,7 +72,7 @@ test('', function () use ($config) {
}); });
test('', function () use ($config) { test('invalid onConnect option triggers exceptions', function () use ($config) {
Assert::exception( Assert::exception(
fn() => new Connection($config + ['onConnect' => '']), fn() => new Connection($config + ['onConnect' => '']),
InvalidArgumentException::class, InvalidArgumentException::class,

View File

@@ -57,28 +57,28 @@ $fluent = $conn->select('*')
->orderBy('customer_id'); ->orderBy('customer_id');
Assert::same( Assert::same(
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'),
(string) $fluent, (string) $fluent,
); );
$fluent->fetch(); $fluent->fetch();
Assert::same( Assert::same(
'SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t', 'SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY',
dibi::$sql, dibi::$sql,
); );
$fluent->fetchSingle(); $fluent->fetchSingle();
Assert::same( Assert::same(
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
$fluent->fetchAll(0, 3); $fluent->fetchAll(0, 3);
Assert::same( Assert::same(
reformat('SELECT TOP (3) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
Assert::same( Assert::same(
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'),
(string) $fluent, (string) $fluent,
); );
@@ -86,16 +86,16 @@ Assert::same(
$fluent->limit(0); $fluent->limit(0);
$fluent->fetch(); $fluent->fetch();
Assert::same( Assert::same(
reformat('SELECT TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 0 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
$fluent->fetchSingle(); $fluent->fetchSingle();
Assert::same( Assert::same(
reformat('SELECT TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 0 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
Assert::same( Assert::same(
reformat('SELECT TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 0 ROWS ONLY'),
(string) $fluent, (string) $fluent,
); );
@@ -104,12 +104,12 @@ $fluent->removeClause('limit');
$fluent->removeClause('offset'); $fluent->removeClause('offset');
$fluent->fetch(); $fluent->fetch();
Assert::same( Assert::same(
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
$fluent->fetchSingle(); $fluent->fetchSingle();
Assert::same( Assert::same(
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'), reformat('SELECT * FROM [customers] ORDER BY [customer_id] OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY'),
dibi::$sql, dibi::$sql,
); );
Assert::same( Assert::same(

View File

@@ -36,5 +36,5 @@ Assert::exception(
test( test(
'PDO error mode: explicitly set silent', 'PDO error mode: explicitly set silent',
fn() => buildPdoDriver(PDO::ERRMODE_SILENT) fn() => buildPdoDriver(PDO::ERRMODE_SILENT),
); );

View File

@@ -18,9 +18,9 @@ $tests = function ($conn) {
Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A%B')->fetchSingle()); Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A%B')->fetchSingle());
Assert::true($conn->query("SELECT 'AA%BB' LIKE %~like~", 'A%B')->fetchSingle()); Assert::true($conn->query("SELECT 'AA%BB' LIKE %~like~", 'A%B')->fetchSingle());
Assert::same('AA\\BB', $conn->query("SELECT 'AA\\BB'")->fetchSingle()); Assert::same('AA\BB', $conn->query("SELECT 'AA\\BB'")->fetchSingle());
Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A\\B')->fetchSingle()); Assert::false($conn->query("SELECT 'AAxBB' LIKE %~like~", 'A\B')->fetchSingle());
Assert::true($conn->query("SELECT 'AA\\BB' LIKE %~like~", 'A\\B')->fetchSingle()); Assert::true($conn->query("SELECT 'AA\\BB' LIKE %~like~", 'A\B')->fetchSingle());
}; };
$conn = new Dibi\Connection($config); $conn = new Dibi\Connection($config);

View File

@@ -25,7 +25,7 @@ class MockResult extends Dibi\Result
} }
test('', function () { test('native text conversion preserves boolean values', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Text); $result->setType('col', Type::Text);
$result->setFormat(Type::Text, 'native'); $result->setFormat(Type::Text, 'native');
@@ -36,7 +36,7 @@ test('', function () {
}); });
test('', function () { test('boolean conversion from diverse representations', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Bool); $result->setType('col', Type::Bool);
@@ -58,7 +58,7 @@ test('', function () {
}); });
test('', function () { test('text conversion of booleans and numerics', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Text); $result->setType('col', Type::Text);
@@ -74,7 +74,7 @@ test('', function () {
}); });
test('', function () { test('float conversion with various numeric formats', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Float); $result->setType('col', Type::Float);
@@ -214,7 +214,7 @@ test('', function () {
}); });
test('', function () { test('strict integer conversion with error on empty string', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Integer); $result->setType('col', Type::Integer);
@@ -222,14 +222,10 @@ test('', function () {
Assert::same(['col' => 1], $result->test(['col' => true])); Assert::same(['col' => 1], $result->test(['col' => true]));
Assert::same(['col' => 0], $result->test(['col' => false])); Assert::same(['col' => 0], $result->test(['col' => false]));
if (PHP_VERSION_ID < 80000) { Assert::exception(
Assert::same(['col' => 0], @$result->test(['col' => ''])); // triggers warning since PHP 7.1 fn() => Assert::same(['col' => 0], $result->test(['col' => ''])),
} else { TypeError::class,
Assert::exception( );
fn() => Assert::same(['col' => 0], $result->test(['col' => ''])),
TypeError::class,
);
}
Assert::same(['col' => 0], $result->test(['col' => '0'])); Assert::same(['col' => 0], $result->test(['col' => '0']));
Assert::same(['col' => 1], $result->test(['col' => '1'])); Assert::same(['col' => 1], $result->test(['col' => '1']));
@@ -248,7 +244,7 @@ test('', function () {
}); });
test('', function () { test('dateTime conversion with object instantiation', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::DateTime); $result->setType('col', Type::DateTime);
@@ -267,7 +263,7 @@ test('', function () {
}); });
test('', function () { test('dateTime conversion using custom format', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::DateTime); $result->setType('col', Type::DateTime);
$result->setFormat(Type::DateTime, 'Y-m-d H:i:s'); $result->setFormat(Type::DateTime, 'Y-m-d H:i:s');
@@ -287,7 +283,7 @@ test('', function () {
}); });
test('', function () { test('date conversion to DateTime instance', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Date); $result->setType('col', Type::Date);
@@ -304,7 +300,7 @@ test('', function () {
}); });
test('', function () { test('time conversion to DateTime instance', function () {
$result = new MockResult; $result = new MockResult;
$result->setType('col', Type::Time); $result->setType('col', Type::Time);

View File

@@ -11,82 +11,59 @@ use Tester\Assert;
require __DIR__ . '/bootstrap.php'; require __DIR__ . '/bootstrap.php';
$tests = function ($conn) { $tests = function ($conn) {
$resource = $conn->getDriver()->getResource(); // Limit and offset
$version = is_resource($resource) Assert::same(
? sqlsrv_server_info($resource)['SQLServerVersion'] 'SELECT 1 OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY',
: $resource->getAttribute(PDO::ATTR_SERVER_VERSION); $conn->translate('SELECT 1 %ofs %lmt', 10, 10),
);
// MsSQL2012+ // Limit only
if (version_compare($version, '11.0') >= 0) { Assert::same(
// Limit and offset 'SELECT 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',
Assert::same( $conn->translate('SELECT 1 %lmt', 10),
'SELECT 1 OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY', );
$conn->translate('SELECT 1 %ofs %lmt', 10, 10),
);
// Limit only // Offset only
Assert::same( Assert::same(
'SELECT 1 OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY', 'SELECT 1 OFFSET 10 ROWS',
$conn->translate('SELECT 1 %lmt', 10), $conn->translate('SELECT 1 %ofs', 10),
); );
// Offset only // Offset invalid
Assert::same( Assert::error(
'SELECT 1 OFFSET 10 ROWS', function () use ($conn) {
$conn->translate('SELECT 1 %ofs', 10), $conn->translate('SELECT 1 %ofs', -10);
); },
Dibi\NotSupportedException::class,
'Negative offset or limit.',
);
// Offset invalid // Limit invalid
Assert::error( Assert::error(
function () use ($conn) { function () use ($conn) {
$conn->translate('SELECT 1 %ofs', -10); $conn->translate('SELECT 1 %lmt', -10);
}, },
Dibi\NotSupportedException::class, Dibi\NotSupportedException::class,
'Negative offset or limit.', 'Negative offset or limit.',
); );
// Limit invalid // Limit invalid, offset valid
Assert::error( Assert::error(
function () use ($conn) { function () use ($conn) {
$conn->translate('SELECT 1 %lmt', -10); $conn->translate('SELECT 1 %ofs %lmt', 10, -10);
}, },
Dibi\NotSupportedException::class, Dibi\NotSupportedException::class,
'Negative offset or limit.', 'Negative offset or limit.',
); );
// Limit invalid, offset valid // Limit valid, offset invalid
Assert::error( Assert::error(
function () use ($conn) { function () use ($conn) {
$conn->translate('SELECT 1 %ofs %lmt', 10, -10); $conn->translate('SELECT 1 %ofs %lmt', -10, 10);
}, },
Dibi\NotSupportedException::class, Dibi\NotSupportedException::class,
'Negative offset or limit.', 'Negative offset or limit.',
); );
// Limit valid, offset invalid
Assert::error(
function () use ($conn) {
$conn->translate('SELECT 1 %ofs %lmt', -10, 10);
},
Dibi\NotSupportedException::class,
'Negative offset or limit.',
);
} else {
Assert::same(
'SELECT TOP (1) * FROM (SELECT 1) t',
$conn->translate('SELECT 1 %lmt', 1),
);
Assert::same(
'SELECT 1',
$conn->translate('SELECT 1 %lmt', -10),
);
Assert::exception(
fn() => $conn->translate('SELECT 1 %ofs %lmt', 10, 10),
Dibi\NotSupportedException::class,
);
}
}; };
$conn = new Dibi\Connection($config); $conn = new Dibi\Connection($config);

View File

@@ -1,7 +1,6 @@
<?php <?php
/** /**
* @phpVersion 8.1
* @dataProvider ../databases.ini * @dataProvider ../databases.ini
*/ */

View File

@@ -32,7 +32,7 @@ Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', "a'a", "a'"));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like~', "b'", "%'")); Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like~', "b'", "%'"));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', "%'", "%'")); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', "%'", "%'"));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', 'a\\a', 'a\\')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', 'a\a', 'a\\'));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like~', 'b\\', '%\\')); Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like~', 'b\\', '%\\'));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', '%\\', '%\\')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like~', '%\\', '%\\'));
@@ -60,9 +60,9 @@ Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', "a'a", "'a"));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like', "'b", "'%")); Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like', "'b", "'%"));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', "'%", "'%")); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', "'%", "'%"));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', 'a\\a', '\\a')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', 'a\a', '\a'));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like', '\\b', '\\%')); Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like', '\b', '\%'));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', '\\%', '\\%')); Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like', '\%', '\%'));
// contains // contains