1
0
mirror of https://github.com/dg/dibi.git synced 2025-08-30 01:09:50 +02:00

Compare commits

...

21 Commits

Author SHA1 Message Date
David Grudl
d70e274244 Released version 4.2.5 2021-11-29 13:48:16 +01:00
David Grudl
e05eb01233 fixed PHP 7.2 compatibility 2021-11-28 15:09:41 +01:00
David Grudl
2ac618ffff Date 0000-01-01 is valid [Closes #402] 2021-11-24 18:34:20 +01:00
Milan Otáhal
1881fea0e5 Profiler is not used in CLI mode 2021-11-24 18:34:20 +01:00
Jan Rössler
cb82357cfb Helpers::detectType(): detect PostgreSQL range types as Type::TEXT 2021-11-24 18:34:20 +01:00
Jan Rössler
0a29fcb502 PostgreReflector: fix reflection of matview columns on PostgreSQL 12+ 2021-11-24 18:34:20 +01:00
David Grudl
8270b7c1c3 support for PHP 8.1 2021-11-24 18:34:20 +01:00
David Grudl
73e16eb1a3 Released version 4.2.3 2021-07-23 10:49:27 +02:00
David Grudl
0b394a993d SqlsrvDriver: fixed after 40ad77cf [Closes #391][Closes #392] 2021-06-30 12:47:45 +02:00
David Grudl
df3edee70b removed travis 2021-04-23 20:54:50 +02:00
David Grudl
245da39a9f added github workflows 2021-04-23 20:53:38 +02:00
David Grudl
3df64fc3b3 fixed tests 2021-04-23 20:48:29 +02:00
David Grudl
95c3f72a17 Released version 4.2.2 2021-04-21 13:56:00 +02:00
David Grudl
d71caf0c75 Row: fixed ?? usage 2021-04-21 13:54:59 +02:00
Miloslav Hůla
3066fea2aa Connection: begin(), commit() & rollback() calls are forbidden in transaction() 2021-04-05 16:50:15 +02:00
Miloslav Hůla
b00e556289 Connection::transtaction() call can be nested 2021-04-05 16:50:15 +02:00
Miloslav Hůla
877dffd460 tests: use test() helper 2021-04-05 13:37:16 +02:00
Miloslav Hůla
7049949b14 Connection::transaction(): pass self as a callback argument 2021-04-05 13:37:16 +02:00
Miloslav Hůla
771e846a62 tests: Sqlite3 driver fix 2021-04-05 13:37:16 +02:00
David Grudl
4e056c52dd updated appveyor.yml 2021-03-10 16:53:34 +01:00
David Grudl
40ad77cf5f SqlsrvDriver: workaround for "Driver's SQLSetConnectAttr failed on ODBC <=13" bug 2021-03-10 16:42:33 +01:00
30 changed files with 463 additions and 194 deletions

31
.github/workflows/coding-style.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Coding Style
on: [push, pull_request]
jobs:
nette_cc:
name: Nette Code Checker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
coverage: none
- run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress
- run: php temp/code-checker/code-checker --strict-types --no-progress --ignore "tests/*/fixtures"
nette_cs:
name: Nette Coding Standard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
coverage: none
- run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress --ignore-platform-reqs
- run: php temp/coding-standard/ecs check

21
.github/workflows/static-analysis.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Static Analysis (only informative)
on:
push:
branches:
- master
jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
coverage: none
- run: composer install --no-progress --prefer-dist
- run: composer phpstan -- --no-progress
continue-on-error: true # is only informative

121
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,121 @@
name: Tests
on: [push, pull_request]
env:
php-extensions: mbstring, intl, mysqli, pgsql, sqlsrv-5.9.0preview1, pdo_sqlsrv-5.9.0preview1
php-tools: "composer:v2, pecl"
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.2', '7.3', '7.4', '8.0', '8.1']
fail-fast: false
name: PHP ${{ matrix.php }} tests
services:
mysql57:
image: mysql:5.7
env:
MYSQL_DATABASE: dibi_test
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
mysql80:
image: mysql:8.0
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping -ppass"
--health-interval=10s
--health-timeout=5s
--health-retries=5
-e MYSQL_ROOT_PASSWORD=root
-e MYSQL_DATABASE=dibi_test
--entrypoint sh mysql:8 -c "exec docker-entrypoint.sh mysqld --default-authentication-plugin=mysql_native_password"
postgres96:
image: postgres:9.6
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: dibi_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres13:
image: postgres:13
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: dibi_test
ports:
- 5433:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mssql:
image: mcr.microsoft.com/mssql/server:latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: YourStrong!Passw0rd
MSSQL_PID: Developer
ports:
- 1433:1433
options: >-
--name=mssql
--health-cmd "/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ env.php-extensions }}
tools: ${{ env.php-tools }}
coverage: none
- name: Create databases.ini
run: cp ./tests/databases.github.ini ./tests/databases.ini
- name: Create MS SQL Database
run: docker exec -i mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'YourStrong!Passw0rd' -Q 'CREATE DATABASE dibi_test'
- run: composer install --no-progress --prefer-dist
- run: vendor/bin/tester -p phpdbg tests -s -C --coverage ./coverage.xml --coverage-src ./src
- if: failure()
uses: actions/upload-artifact@v2
with:
name: output
path: tests/**/output
- name: Save Code Coverage
if: ${{ matrix.php == '8.0' }}
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar
php php-coveralls.phar --verbose --config tests/.coveralls.yml

View File

@@ -1,76 +0,0 @@
language: php
php:
- 7.2
- 7.3
- 7.4
- 8.0snapshot
services:
- mysql
- postgresql
before_install:
# turn off XDebug
- phpenv config-rm xdebug.ini || return 0
# Create databases.ini
- cp ./tests/databases.travis.ini ./tests/databases.ini
# Create Postgre database
- psql -c 'CREATE DATABASE dibi_test' -U postgres
install:
- travis_retry composer install --no-progress --prefer-dist
script:
- vendor/bin/tester tests -s
after_failure:
# Print *.actual content
- for i in $(find tests -name \*.actual); do echo "--- $i"; cat $i; echo; echo; done
jobs:
include:
- name: Nette Code Checker
install:
- travis_retry composer create-project nette/code-checker temp/code-checker ^3 --no-progress
script:
- php temp/code-checker/code-checker --strict-types
- name: Nette Coding Standard
php: 7.4
install:
- travis_retry composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress
script:
- php temp/coding-standard/ecs check src tests
- stage: Static Analysis (informative)
php: 7.4
script:
- composer run-script phpstan
- stage: Code Coverage
php: 7.4
script:
- vendor/bin/tester -p phpdbg tests -s --coverage ./coverage.xml --coverage-src ./src
after_script:
- wget https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar
- php coveralls.phar --verbose --config tests/.coveralls.yml
allow_failures:
- stage: Static Analysis (informative)
- stage: Code Coverage
dist: xenial
cache:
directories:
- $HOME/.composer/cache
notifications:
email: false

View File

@@ -15,17 +15,17 @@ init:
- SET ANSICON=121x90 (121x90)
install:
# Install PHP 7.1
# Install PHP 7.2
- IF EXIST c:\php7 (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php7
- IF %PHP%==1 cd c:\php7
- IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.1.5-Win32-VC14-x64.zip --output php.zip
- IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.2.18-Win32-VC15-x64.zip --output php.zip
- IF %PHP%==1 7z x php.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
- IF %PHP%==1 appveyor DownloadFile https://files.nette.org/misc/php-sqlsrv.zip
- IF %PHP%==1 7z x php-sqlsrv.zip >nul
- IF %PHP%==1 copy SQLSRV\php_sqlsrv_71_ts.dll ext\php_sqlsrv_71_ts.dll
- IF %PHP%==1 curl https://github.com/microsoft/msphpsql/releases/download/v5.8.0/Windows-7.2.zip -L --output sqlsrv.zip
- IF %PHP%==1 7z x sqlsrv.zip >nul
- IF %PHP%==1 copy Windows-7.2\x64\php_sqlsrv_72_ts.dll ext\php_sqlsrv_ts.dll
- IF %PHP%==1 del /Q *.zip
# Install Microsoft Access Database Engine x64

View File

@@ -2,7 +2,7 @@
=========================================================
[![Downloads this Month](https://img.shields.io/packagist/dm/dibi/dibi.svg)](https://packagist.org/packages/dibi/dibi)
[![Build Status](https://travis-ci.org/dg/dibi.svg?branch=master)](https://travis-ci.org/dg/dibi)
[![Tests](https://github.com/dg/dibi/workflows/Tests/badge.svg?branch=master)](https://github.com/dg/dibi/actions)
[![Build Status Windows](https://ci.appveyor.com/api/projects/status/github/dg/dibi?branch=master&svg=true)](https://ci.appveyor.com/project/dg/dibi/branch/master)
[![Latest Stable Version](https://poser.pugx.org/dibi/dibi/v/stable)](https://github.com/dg/dibi/releases)
[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/dg/dibi/blob/master/license.md)
@@ -34,7 +34,7 @@ Install Dibi via Composer:
composer require dibi/dibi
```
The Dibi 4.2 requires PHP version 7.2 and supports PHP up to 8.0.
The Dibi 4.2 requires PHP version 7.2 and supports PHP up to 8.1.
Usage

View File

@@ -22,10 +22,14 @@ class DibiExtension22 extends Nette\DI\CompilerExtension
/** @var bool|null */
private $debugMode;
/** @var bool|null */
private $cliMode;
public function __construct(bool $debugMode = null)
public function __construct(bool $debugMode = null, bool $cliMode = null)
{
$this->debugMode = $debugMode;
$this->cliMode = $cliMode;
}
@@ -38,7 +42,11 @@ class DibiExtension22 extends Nette\DI\CompilerExtension
$this->debugMode = $container->parameters['debugMode'];
}
$useProfiler = $config['profiler'] ?? (class_exists(Tracy\Debugger::class) && $this->debugMode);
if ($this->cliMode === null) {
$this->cliMode = $container->parameters['consoleMode'];
}
$useProfiler = $config['profiler'] ?? (class_exists(Tracy\Debugger::class) && $this->debugMode && !$this->cliMode);
unset($config['profiler']);

View File

@@ -40,6 +40,8 @@ class Connection implements IConnection
/** @var HashMap Substitutes for identifiers */
private $substitutes;
private $transactionDepth = 0;
/**
* Connection options: (see driver-specific options too)
@@ -335,6 +337,10 @@ class Connection implements IConnection
*/
public function begin(string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
@@ -359,6 +365,10 @@ class Connection implements IConnection
*/
public function commit(string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
@@ -383,6 +393,10 @@ class Connection implements IConnection
*/
public function rollback(string $savepoint = null): void
{
if ($this->transactionDepth !== 0) {
throw new \LogicException(__METHOD__ . '() call is forbidden inside a transaction() callback');
}
if (!$this->driver) {
$this->connect();
}
@@ -407,14 +421,26 @@ class Connection implements IConnection
*/
public function transaction(callable $callback)
{
$this->begin();
if ($this->transactionDepth === 0) {
$this->begin();
}
$this->transactionDepth++;
try {
$res = $callback();
$res = $callback($this);
} catch (\Throwable $e) {
$this->rollback();
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->rollback();
}
throw $e;
}
$this->commit();
$this->transactionDepth--;
if ($this->transactionDepth === 0) {
$this->commit();
}
return $res;
}

View File

@@ -72,7 +72,7 @@ class MySqliDriver implements Dibi\Driver
$host = ini_get('mysqli.default_host');
if ($host) {
$config['host'] = $host;
$config['port'] = ini_get('mysqli.default_port');
$config['port'] = (int) ini_get('mysqli.default_port');
} else {
$config['host'] = null;
$config['port'] = null;

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi;
use Dibi\Helpers;
use PgSql;
/**
@@ -29,7 +30,7 @@ class PostgreDriver implements Dibi\Driver
{
use Dibi\Strict;
/** @var resource */
/** @var resource|PgSql\Connection */
private $connection;
/** @var int|null Affected rows */
@@ -74,7 +75,7 @@ class PostgreDriver implements Dibi\Driver
restore_error_handler();
}
if (!is_resource($this->connection)) {
if (!is_resource($this->connection) && !$this->connection instanceof PgSql\Connection) {
throw new Dibi\DriverException($error ?: 'Connecting error.');
}
@@ -120,7 +121,7 @@ class PostgreDriver implements Dibi\Driver
if ($res === false) {
throw static::createException(pg_last_error($this->connection), null, $sql);
} elseif (is_resource($res)) {
} elseif (is_resource($res) || $res instanceof PgSql\Result) {
$this->affectedRows = Helpers::false2Null(pg_affected_rows($res));
if (pg_num_fields($res)) {
return $this->createResultDriver($res);
@@ -227,7 +228,9 @@ class PostgreDriver implements Dibi\Driver
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : null;
return is_resource($this->connection) || $this->connection instanceof PgSql\Connection
? $this->connection
: null;
}
@@ -258,7 +261,7 @@ class PostgreDriver implements Dibi\Driver
*/
public function escapeText(string $value): string
{
if (!is_resource($this->connection)) {
if (!$this->getResource()) {
throw new Dibi\Exception('Lost connection to server.');
}
return "'" . pg_escape_string($this->connection, $value) . "'";
@@ -267,7 +270,7 @@ class PostgreDriver implements Dibi\Driver
public function escapeBinary(string $value): string
{
if (!is_resource($this->connection)) {
if (!$this->getResource()) {
throw new Dibi\Exception('Lost connection to server.');
}
return "'" . pg_escape_bytea($this->connection, $value) . "'";

View File

@@ -102,7 +102,7 @@ class PostgreReflector implements Dibi\Reflector
a.atttypmod-4 AS character_maximum_length,
NOT a.attnotnull AS is_nullable,
a.attnum AS ordinal_position,
adef.adsrc AS column_default
pg_get_expr(adef.adbin, adef.adrelid) AS column_default
FROM
pg_attribute a
JOIN pg_type ON a.atttypid = pg_type.oid

View File

@@ -11,6 +11,7 @@ namespace Dibi\Drivers;
use Dibi;
use Dibi\Helpers;
use PgSql;
/**
@@ -20,7 +21,7 @@ class PostgreResult implements Dibi\ResultDriver
{
use Dibi\Strict;
/** @var resource */
/** @var resource|PgSql\Result */
private $resultSet;
/** @var bool */
@@ -28,7 +29,7 @@ class PostgreResult implements Dibi\ResultDriver
/**
* @param resource $resultSet
* @param resource|PgSql\Result $resultSet
*/
public function __construct($resultSet)
{
@@ -108,12 +109,14 @@ class PostgreResult implements Dibi\ResultDriver
/**
* Returns the result set resource.
* @return resource|null
* @return resource|PgSql\Result|null
*/
public function getResultResource()
{
$this->autoFree = false;
return is_resource($this->resultSet) ? $this->resultSet : null;
return is_resource($this->resultSet) || $this->resultSet instanceof PgSql\Result
? $this->resultSet
: null;
}

View File

@@ -53,6 +53,9 @@ class SqlsrvDriver implements Dibi\Driver
if (isset($config['resource'])) {
$this->connection = $config['resource'];
if (!is_resource($this->connection)) {
throw new \InvalidArgumentException("Configuration option 'resource' is not resource.");
}
} else {
$options = $config['options'];
@@ -63,13 +66,15 @@ class SqlsrvDriver implements Dibi\Driver
$options['UID'] = (string) $options['UID'];
$options['Database'] = (string) $options['Database'];
sqlsrv_configure('WarningsReturnAsErrors', 0);
$this->connection = sqlsrv_connect($config['host'], $options);
if (!is_resource($this->connection)) {
$info = sqlsrv_errors(SQLSRV_ERR_ERRORS);
throw new Dibi\DriverException($info[0]['message'], $info[0]['code']);
}
sqlsrv_configure('WarningsReturnAsErrors', 1);
}
if (!is_resource($this->connection)) {
$info = sqlsrv_errors();
throw new Dibi\DriverException($info[0]['message'], $info[0]['code']);
}
$this->version = sqlsrv_server_info($this->connection)['SQLServerVersion'];
}

View File

@@ -181,6 +181,7 @@ class Helpers
{
static $patterns = [
'^_' => Type::TEXT, // PostgreSQL arrays
'RANGE$' => Type::TEXT, // PostgreSQL range types
'BYTEA|BLOB|BIN' => Type::BINARY,
'TEXT|CHAR|POINT|INTERVAL|STRING' => Type::TEXT,
'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT|^TINY$' => Type::INTEGER,

View File

@@ -489,7 +489,7 @@ class Result implements IDataSource
$row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
} elseif ($type === Type::DATETIME || $type === Type::DATE || $type === Type::TIME) {
if ($value && substr((string) $value, 0, 3) !== '000') { // '', null, false, '0000-00-00', ...
if ($value && substr((string) $value, 0, 7) !== '0000-00') { // '', null, false, '0000-00-00', ...
$value = new DateTime($value);
$row[$key] = $format ? $value->format($format) : $value;
} else {

View File

@@ -44,6 +44,7 @@ class ResultIterator implements \Iterator, \Countable
}
#[\ReturnTypeWillChange]
/**
* Returns the key of the current element.
* @return mixed
@@ -54,6 +55,7 @@ class ResultIterator implements \Iterator, \Countable
}
#[\ReturnTypeWillChange]
/**
* Returns the current element.
* @return mixed

View File

@@ -37,7 +37,7 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
{
$time = $this[$key];
if (!$time instanceof DateTime) {
if (!$time || substr((string) $time, 0, 3) === '000') { // '', null, false, '0000-00-00', ...
if (!$time || substr((string) $time, 0, 7) === '0000-00') { // '', null, false, '0000-00-00', ...
return null;
}
$time = new DateTime($time);
@@ -53,40 +53,47 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
}
public function __isset(string $key): bool
{
return false;
}
/********************* interfaces ArrayAccess, Countable & IteratorAggregate ****************d*g**/
final public function count()
final public function count(): int
{
return count((array) $this);
}
final public function getIterator()
final public function getIterator(): \ArrayIterator
{
return new \ArrayIterator($this);
}
final public function offsetSet($nm, $val)
final public function offsetSet($nm, $val): void
{
$this->$nm = $val;
}
#[\ReturnTypeWillChange]
final public function offsetGet($nm)
{
return $this->$nm;
}
final public function offsetExists($nm)
final public function offsetExists($nm): bool
{
return isset($this->$nm);
}
final public function offsetUnset($nm)
final public function offsetUnset($nm): void
{
unset($this->$nm);
}

View File

@@ -45,7 +45,7 @@ class dibi
/** version */
public const
VERSION = '4.2.1';
VERSION = '4.2.5';
/** sorting order */
public const

View File

@@ -1,4 +1,4 @@
# for php-coveralls
service_name: travis-ci
service_name: github-actions
coverage_clover: coverage.xml
json_path: coverage.json

View File

@@ -0,0 +1,89 @@
[sqlite] ; default
driver = sqlite
database = :memory:
system = sqlite
[sqlite pdo]
driver = pdo
dsn = "sqlite::memory:"
system = sqlite
[mysql 5.7]
driver = mysqli
host = "127.0.0.1"
database = dibi_test
username = root
password = root
port = 3306
system = mysql
[mysql 5.7pdo]
driver = pdo
dsn = "mysql:host=127.0.0.1;port=3306;dbname=dibi_test"
user = root
password = root
system = mysql
[mysql 8.0]
driver = mysqli
host = "127.0.0.1"
database = dibi_test
username = root
password = root
port = 3307
system = mysql
[mysql 8.0pdo]
driver = pdo
dsn = "mysql:host=127.0.0.1;port=3307;dbname=dibi_test"
user = root
password = root
system = mysql
[postgre 9.6]
driver = postgre
host = "127.0.0.1"
database = dibi_test
username = postgres
password = postgres
port = 5432
system = postgre
[postgre 9.6pdo]
driver = pdo
dsn = "pgsql:host=127.0.0.1;port=5432;dbname=dibi_test"
user = postgres
password = postgres
system = postgre
[postgre 13]
driver = postgre
host = "127.0.0.1"
database = dibi_test
username = postgres
password = postgres
port = 5433
system = postgre
[postgre 13pdo]
driver = pdo
dsn = "pgsql:host=127.0.0.1;port=5433;dbname=dibi_test"
user = postgres
password = postgres
system = postgre
[sqlsrv]
driver = sqlsrv
host = "localhost"
username = SA
password = "YourStrong!Passw0rd"
database = dibi_test
port = 1433
system = sqlsrv
;[sqlsrv pdo]
;driver = pdo
;dsn = "sqlsrv:Server=localhost,1433;Database=dibi_test"
;user = SA
;password = "YourStrong!Passw0rd"
;system = sqlsrv

View File

@@ -1,38 +0,0 @@
[sqlite] ; default
driver = sqlite
database = :memory:
system = sqlite
[sqlite pdo]
driver = pdo
dsn = "sqlite::memory:"
system = sqlite
[mysql improved]
driver = mysqli
host = 127.0.0.1
username = root
password =
charset = utf8
system = mysql
[mysql pdo]
driver = pdo
dsn = "mysql:host=127.0.0.1"
username = root
password =
system = mysql
[postgre]
driver = postgre
host = 127.0.0.1
username = postgres
password =
system = postgre
[postgre pdo]
driver = pdo
dsn = "pgsql:host=127.0.0.1;dbname=dibi_test"
username = postgres
password =
system = postgre

View File

@@ -30,42 +30,102 @@ Assert::exception(function () use ($conn) {
*/
$conn->begin();
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->rollback();
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->begin();
$conn->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$conn->commit();
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
Assert::exception(function () use ($conn) {
$conn->transaction(function () use ($conn) {
$conn->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
throw new Exception('my exception');
});
}, \Throwable::class, 'my exception');
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->transaction(function () use ($conn) {
test('begin() & rollback()', function () use ($conn) {
$conn->begin();
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
$conn->rollback();
Assert::same(3, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
test('begin() & commit()', function () use ($conn) {
$conn->begin();
$conn->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$conn->commit();
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('transaction() fail', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
throw new Exception('my exception');
});
}, \Throwable::class, 'my exception');
Assert::same(4, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('transaction() success', function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
});
Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('nested transaction() call fail', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$connection->transaction(function (Dibi\Connection $connection2) {
$connection2->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
throw new Exception('my exception');
});
});
}, \Throwable::class, 'my exception');
Assert::same(5, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('nested transaction() call success', function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
$connection->transaction(function (Dibi\Connection $connection2) {
$connection2->query('INSERT INTO [products]', [
'title' => 'Test product',
]);
});
});
Assert::same(7, (int) $conn->query('SELECT COUNT(*) FROM [products]')->fetchSingle());
});
test('begin(), commit() & rollback() calls are forbidden in transaction()', function () use ($conn) {
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->begin();
});
}, \LogicException::class, Dibi\Connection::class . '::begin() call is forbidden inside a transaction() callback');
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->commit();
});
}, \LogicException::class, Dibi\Connection::class . '::commit() call is forbidden inside a transaction() callback');
Assert::exception(function () use ($conn) {
$conn->transaction(function (Dibi\Connection $connection) {
$connection->rollback();
});
}, \LogicException::class, Dibi\Connection::class . '::rollback() call is forbidden inside a transaction() callback');
});

View File

@@ -14,8 +14,6 @@ Assert::same('1978-01-23 11:40:00.000000', (string) new DateTime(254400000));
Assert::same('1978-01-23 11:40:00.000000', (string) (new DateTime)->setTimestamp(254400000));
Assert::same(254400000, (new DateTime(254400000))->getTimestamp());
Assert::same('2050-08-13 11:40:00.000000', (string) new DateTime(2544000000));
Assert::same('2050-08-13 11:40:00.000000', (string) (new DateTime)->setTimestamp(2544000000));
Assert::same(is_int(2544000000) ? 2544000000 : '2544000000', (new DateTime(2544000000))->getTimestamp()); // 64 bit
Assert::same('1978-05-05 00:00:00.000000', (string) new DateTime('1978-05-05'));

View File

@@ -32,7 +32,7 @@ Assert::same(
);
if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) {
if (!in_array($config['driver'], ['sqlite', 'sqlite3', 'pdo', 'sqlsrv'], true)) {
Assert::same(
['products.product_id', 'orders.order_id', 'customers.name', 'xXx'],
$info->getColumnNames(true)
@@ -43,7 +43,7 @@ if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) {
$columns = $info->getColumns();
Assert::same('product_id', $columns[0]->getName());
if (!in_array($config['driver'], ['sqlite', 'pdo', 'sqlsrv'], true)) {
if (!in_array($config['driver'], ['sqlite', 'sqlite3', 'pdo', 'sqlsrv'], true)) {
Assert::same('products', $columns[0]->getTableName());
}
Assert::null($columns[0]->getVendorInfo('xxx'));

View File

@@ -35,6 +35,10 @@ Assert::error(function () use ($row) {
Assert::false(isset($row->missing));
Assert::false(isset($row['missing']));
// ??
Assert::same(123, $row->missing ?? 123);
Assert::same(123, $row['missing'] ?? 123);
// suggestions
Assert::error(function () use ($row) {

View File

@@ -1,7 +1,7 @@
<?php
/**
* @dataProvider ../databases.ini
* @dataProvider ../databases.ini !=sqlsrv
*/
declare(strict_types=1);

View File

@@ -23,6 +23,10 @@ try {
$config = reset($config);
}
if (isset($config['port'])) {
$config['port'] = (int) $config['port'];
}
// lock
define('TEMP_DIR', __DIR__ . '/../tmp');

View File

@@ -36,7 +36,7 @@ Assert::same('SELECT', $e->getSql());
$e = Assert::exception(function () use ($conn) {
$conn->query('INSERT INTO products (product_id, title) VALUES (1, "New")');
}, Dibi\UniqueConstraintViolationException::class, "%a?%Duplicate entry '1' for key 'PRIMARY'", 1062);
}, Dibi\UniqueConstraintViolationException::class, "%a?%Duplicate entry '1' for key '%a?%PRIMARY'", 1062);
Assert::same("INSERT INTO products (product_id, title) VALUES (1, 'New')", $e->getSql());

View File

@@ -31,7 +31,7 @@ Assert::same("INSERT INTO products (product_id, title) VALUES (1, 'New')", $e->g
$e = Assert::exception(function () use ($conn) {
$conn->query('INSERT INTO products (title) VALUES (NULL)');
}, Dibi\NotNullConstraintViolationException::class, '%a?%null value in column "title" violates not-null constraint%A?%', '23502');
}, Dibi\NotNullConstraintViolationException::class, '%a?%null value in column "title"%a%violates not-null constraint%A?%', '23502');
Assert::same('INSERT INTO products (title) VALUES (NULL)', $e->getSql());

View File

@@ -12,5 +12,5 @@ extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
extension=php_pgsql.dll
extension=php_sqlite3.dll
extension=php_sqlsrv_71_ts.dll
extension=php_sqlsrv_ts.dll
extension=php_odbc.dll