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

Compare commits

..

26 Commits

Author SHA1 Message Date
David Grudl
dbbf0ca673 Revert "PhpStan fixes (#363)"
This reverts commit 68f9d0981f194931e475e2c93730d8e8785c20e4.
2020-05-07 21:42:36 +02:00
Jan Barášek
1bdf6e93d0 PhpStan fixes (#363) 2020-05-07 21:41:28 +02:00
David Grudl
ed2a827419 Released version 4.1.3 2020-03-26 04:10:39 +01:00
David Grudl
e46be6cee6 SqliteResult: workaround for PHP bug 79414 2020-03-26 04:10:39 +01:00
David Grudl
0f69d5d32c Result: does not drop the value if detection fails 2020-03-26 04:10:39 +01:00
Adam Klvač
e826e3a719 MySqliDriver: coalesced password to an empty string (#360)
mysqli::real_connect() expects parameter 3 to be string, yields an error on NULL.
2020-03-26 03:32:03 +01:00
David Grudl
6eac117f5f Result::fetchAssoc() DateTime in key is converted to string [Closes #359] 2020-03-03 17:18:37 +01:00
David Grudl
2a2c814b0a readme.md: updated 2020-03-03 16:50:43 +01:00
David Grudl
dfab3d711c added DummyDriver 2020-03-03 16:21:21 +01:00
David Grudl
34e16031f7 added phpstan.neon 2020-02-23 19:15:59 +01:00
David Grudl
73160e9418 travis: uses PHP 7.4 for coding checks 2020-02-23 19:08:21 +01:00
David Grudl
f18056a066 Released version 4.1.2 2020-02-23 18:50:27 +01:00
Milan Pála
0bd222b3f1 tests: added reconnect test (#352) 2020-02-23 18:50:27 +01:00
David Grudl
9f71f39470 Connection: translator is created/destructed in connect/disconnect [Closes #352][Closes #354] 2020-02-23 18:50:27 +01:00
Enrico Dias
0b0d805040 FileLogger: refactoring (#351) 2020-02-09 17:22:55 +01:00
Enrico Dias
8c761eac5c FileLogger: Add option to log errors only (#351) 2020-02-09 17:17:05 +01:00
groupnet
2f857c28d6 PostgreDriver: fixed persistent connections (#348)
- https://www.php.net/manual/en/function.pg-pconnect.php
2020-01-24 13:41:57 +01:00
David Grudl
efe1cbdc20 cs 2020-01-12 13:46:23 +01:00
David Grudl
21dad1d846 composer: license clarification 2020-01-07 11:53:19 +01:00
David Grudl
7d55fd03b0 composer: added PHPStan 2019-12-11 21:05:37 +01:00
Ashus
294787a26e Add support for escapeLike without % on any side (#346) (BC break) 2019-11-25 14:01:24 +01:00
David Grudl
9d4bef53d3 travis: added PHP 7.4 2019-11-19 20:15:32 +01:00
David Grudl
1db63d81e9 fixes for PHP 7.4 2019-11-19 01:49:22 +01:00
Adam Klvač
c7dee4d822 SqlsrvResult: fixed illegal false return value from sqlsrv_fetch_array() (#344)
On error, sqlsrv_fetch_array() returns false, which causes an error due to the return type declaration. This commit handles that by casting such value to null the same way other result drivers do it.
2019-11-19 01:30:34 +01:00
Miloslav Hůla
f2927a1b08 OracleResult: LONG type is textual [Closes #342] (#343) 2019-11-06 16:43:33 +01:00
David Grudl
b5a66fdb26 typo 2019-10-22 19:39:16 +02:00
30 changed files with 354 additions and 129 deletions

View File

@@ -3,6 +3,7 @@ php:
- 7.1
- 7.2
- 7.3
- 7.4
services:
- mysql
@@ -31,6 +32,7 @@ after_failure:
jobs:
include:
- name: Nette Code Checker
php: 7.4
install:
- travis_retry composer create-project nette/code-checker temp/code-checker ^3 --no-progress
script:
@@ -38,6 +40,7 @@ jobs:
- name: Nette Coding Standard
php: 7.4
install:
- travis_retry composer create-project nette/coding-standard temp/coding-standard ^2 --no-progress
script:
@@ -45,15 +48,13 @@ jobs:
- stage: Static Analysis (informative)
install:
# Install PHPStan
- travis_retry composer create-project phpstan/phpstan-shim temp/phpstan --no-progress
- travis_retry composer install --no-progress --prefer-dist
php: 7.4
script:
- php temp/phpstan/phpstan.phar analyse --autoload-file vendor/autoload.php --level 5 src
- 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:

View File

@@ -3,7 +3,7 @@
"description": "Dibi is Database Abstraction Library for PHP",
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "sqlsrv", "oracle", "access", "pdo", "odbc"],
"homepage": "https://dibiphp.com",
"license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
"authors": [
{
"name": "David Grudl",
@@ -15,7 +15,8 @@
},
"require-dev": {
"tracy/tracy": "~2.2",
"nette/tester": "~2.0"
"nette/tester": "~2.0",
"phpstan/phpstan": "^0.12"
},
"replace": {
"dg/dibi": "*"
@@ -23,6 +24,10 @@
"autoload": {
"classmap": ["src/"]
},
"scripts": {
"phpstan": "phpstan analyse --autoload-file vendor/autoload.php --level 5 --configuration tests/phpstan.neon src",
"tester": "tester tests -s"
},
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"

View File

@@ -20,6 +20,7 @@ $dibi = new Dibi\Connection([
// enable query logging to this file
'profiler' => [
'file' => 'log/log.sql',
'errorsOnly' => false,
],
]);

View File

@@ -26,7 +26,7 @@ Install Dibi via Composer:
composer require dibi/dibi
```
The Dibi 4.0 requires PHP version 7.1 and supports PHP up to 7.2. Older Dibi 3.x requires PHP 5.4 and supports PHP up to 7.2.
The Dibi 4.1 requires PHP version 7.1 and supports PHP up to 7.4.
Usage
@@ -75,6 +75,8 @@ In the event of a connection error, it throws `Dibi\Exception`.
We query the database queries by the method `query()` which returns `Dibi\Result`. Rows are objects `Dibi\Row`.
You can try all the examples [online at the playground](https://repl.it/@DavidGrudl/dibi-playground).
```php
$result = $database->query('SELECT * FROM users');
@@ -183,7 +185,7 @@ $result = $database->query('SELECT * FROM users WHERE id IN (%i)', $ids);
// SELECT * FROM users WHERE id IN (10, 20, 30)
```
The modifier '%n' is used if the table or column name is a variable. (Beware, do not allow the user to manipulate the content of such a variable):
The modifier `%n` is used if the table or column name is a variable. (Beware, do not allow the user to manipulate the content of such a variable):
```php
$table = 'blog.users';
@@ -199,6 +201,7 @@ Three special modifiers are available for LIKE:
| `%like~` | the expression starts with a string
| `%~like` | the expression ends with a string
| `%~like~` | the expression contains a string
| `%like` | the expression matches a string
Search for names beginning with a string:

View File

@@ -51,6 +51,7 @@ class Connection implements IConnection
* - profiler (array)
* - run (bool) => enable profiler?
* - file => file to log
* - errorsOnly (bool) => log only errors
* - substitutes (array) => map of driver specific substitutes (under development)
* - onConnect (array) => list of SQL queries to execute (by Connection::query()) after connection is established
* @throws Exception
@@ -70,7 +71,8 @@ class Connection implements IConnection
// profiler
if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
$filter = $config['profiler']['filter'] ?? Event::QUERY;
$this->onEvent[] = [new Loggers\FileLogger($config['profiler']['file'], $filter), 'logEvent'];
$errorsOnly = $config['profiler']['errorsOnly'] ?? false;
$this->onEvent[] = [new Loggers\FileLogger($config['profiler']['file'], $filter, $errorsOnly), 'logEvent'];
}
$this->substitutes = new HashMap(function (string $expr) { return ":$expr:"; });
@@ -108,6 +110,7 @@ class Connection implements IConnection
{
if ($this->config['driver'] instanceof Driver) {
$this->driver = $this->config['driver'];
$this->translator = new Translator($this);
return;
} elseif (is_subclass_of($this->config['driver'], Driver::class)) {
@@ -124,6 +127,8 @@ class Connection implements IConnection
$event = $this->onEvent ? new Event($this, Event::CONNECT) : null;
try {
$this->driver = new $class($this->config);
$this->translator = new Translator($this);
if ($event) {
$this->onEvent($event->done());
}
@@ -149,7 +154,7 @@ class Connection implements IConnection
{
if ($this->driver) {
$this->driver->disconnect();
$this->driver = null;
$this->driver = $this->translator = null;
}
}
@@ -250,11 +255,7 @@ class Connection implements IConnection
if (!$this->driver) {
$this->connect();
}
if (!$this->translator) {
$this->translator = new Translator($this);
}
$translator = clone $this->translator;
return $translator->translate($args);
return (clone $this->translator)->translate($args);
}

View File

@@ -0,0 +1,219 @@
<?php
/**
* This file is part of the Dibi, smart database abstraction layer (https://dibiphp.com)
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
declare(strict_types=1);
namespace Dibi\Drivers;
use Dibi;
/**
* The dummy driver for testing purposes.
*/
class DummyDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
{
use Dibi\Strict;
public function disconnect(): void
{
}
public function query(string $sql): ?Dibi\ResultDriver
{
return null;
}
public function getAffectedRows(): ?int
{
return null;
}
public function getInsertId(?string $sequence): ?int
{
return null;
}
public function begin(string $savepoint = null): void
{
}
public function commit(string $savepoint = null): void
{
}
public function rollback(string $savepoint = null): void
{
}
public function getResource()
{
return null;
}
/**
* Returns the connection reflector.
*/
public function getReflector(): Dibi\Reflector
{
return $this;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
*/
public function escapeText(string $value): string
{
return "'" . str_replace("'", "''", $value) . "'";
}
public function escapeBinary(string $value): string
{
return "N'" . str_replace("'", "''", $value) . "'";
}
public function escapeIdentifier(string $value): string
{
return '[' . strtr($value, '[]', ' ') . ']';
}
public function escapeBool(bool $value): string
{
return $value ? '1' : '0';
}
public function escapeDate(\DateTimeInterface $value): string
{
return $value->format("'Y-m-d'");
}
public function escapeDateTime(\DateTimeInterface $value): string
{
return $value->format("'Y-m-d H:i:s.u'");
}
public function escapeDateInterval(\DateInterval $value): string
{
throw new Dibi\NotImplementedException;
}
/**
* Encodes string for use in a LIKE statement.
*/
public function escapeLike(string $value, int $pos): string
{
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}
/**
* Injects LIMIT/OFFSET to the SQL query.
*/
public function applyLimit(string &$sql, ?int $limit, ?int $offset): void
{
if ($limit < 0 || $offset < 0) {
throw new Dibi\NotSupportedException('Negative offset or limit.');
} elseif ($limit !== null || $offset) {
$sql .= ' LIMIT ' . ($limit ?? '-1')
. ($offset ? ' OFFSET ' . $offset : '');
}
}
/********************* Result ****************d*g**/
public function getRowCount(): int
{
return 0;
}
public function fetch(bool $assoc): ?array
{
return null;
}
public function seek(int $row): bool
{
return false;
}
public function free(): void
{
}
public function getResultResource()
{
}
public function getResultColumns(): array
{
return [];
}
/**
* Decodes data from result set.
*/
public function unescapeBinary(string $value): string
{
return $value;
}
/********************* Reflector ****************d*g**/
public function getTables(): array
{
return [];
}
public function getColumns(string $table): array
{
return [];
}
public function getIndexes(string $table): array
{
return [];
}
public function getForeignKeys(string $table): array
{
return [];
}
}

View File

@@ -40,9 +40,7 @@ class FirebirdDriver implements Dibi\Driver
private $inTransaction = false;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('interbase')) {
@@ -271,7 +269,7 @@ class FirebirdDriver implements Dibi\Driver
public function escapeLike(string $value, int $pos): string
{
$value = addcslashes($this->escapeText($value), '%_\\');
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
}

View File

@@ -47,9 +47,7 @@ class MySqliDriver implements Dibi\Driver
private $buffered;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('mysqli')) {
@@ -93,7 +91,7 @@ class MySqliDriver implements Dibi\Driver
@$this->connection->real_connect( // intentionally @
(empty($config['persistent']) ? '' : 'p:') . $config['host'],
$config['username'],
$config['password'],
$config['password'] ?? '',
$config['database'] ?? '',
$config['port'] ?? 0,
$config['socket'],
@@ -317,7 +315,7 @@ class MySqliDriver implements Dibi\Driver
public function escapeLike(string $value, int $pos): string
{
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}

View File

@@ -37,9 +37,7 @@ class OdbcDriver implements Dibi\Driver
private $microseconds = true;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('odbc')) {
@@ -250,7 +248,7 @@ class OdbcDriver implements Dibi\Driver
public function escapeLike(string $value, int $pos): string
{
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}

View File

@@ -42,9 +42,7 @@ class OracleDriver implements Dibi\Driver
private $affectedRows;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('oci8')) {
@@ -270,7 +268,7 @@ class OracleDriver implements Dibi\Driver
{
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
$value = str_replace("'", "''", $value);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}

View File

@@ -96,6 +96,7 @@ class OracleResult implements Dibi\ResultDriver
'name' => oci_field_name($this->resultSet, $i),
'table' => null,
'fullname' => oci_field_name($this->resultSet, $i),
'type' => $type === 'LONG' ? Dibi\Type::TEXT : null,
'nativetype' => $type === 'NUMBER' && oci_field_scale($this->resultSet, $i) === 0 ? 'INTEGER' : $type,
];
}

View File

@@ -42,9 +42,7 @@ class PdoDriver implements Dibi\Driver
private $serverVersion = '';
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('pdo')) {
@@ -324,29 +322,29 @@ class PdoDriver implements Dibi\Driver
switch ($this->driverName) {
case 'mysql':
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
case 'oci':
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
$value = str_replace("'", "''", $value);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
case 'pgsql':
$bs = substr($this->connection->quote('\\', PDO::PARAM_STR), 1, -1); // standard_conforming_strings = on/off
$value = substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1);
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
case 'sqlite':
$value = addcslashes(substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1), '%_\\');
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
case 'odbc':
case 'mssql':
case 'dblib':
case 'sqlsrv':
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
default:
throw new Dibi\NotImplementedException;

View File

@@ -35,9 +35,7 @@ class PostgreDriver implements Dibi\Driver
private $affectedRows;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('pgsql')) {
@@ -71,7 +69,7 @@ class PostgreDriver implements Dibi\Driver
if (empty($config['persistent'])) {
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
} else {
$this->connection = pg_pconnect($string, PGSQL_CONNECT_FORCE_NEW);
$this->connection = pg_pconnect($string);
}
restore_error_handler();
}
@@ -318,7 +316,7 @@ class PostgreDriver implements Dibi\Driver
$bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off
$value = pg_escape_string($this->connection, $value);
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}

View File

@@ -37,9 +37,7 @@ class SqliteDriver implements Dibi\Driver
private $fmtDateTime;
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('sqlite3')) {
@@ -254,7 +252,7 @@ class SqliteDriver implements Dibi\Driver
public function escapeLike(string $value, int $pos): string
{
$value = addcslashes($this->connection->escapeString($value), '%_\\');
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
}

View File

@@ -96,7 +96,7 @@ class SqliteResult implements Dibi\ResultDriver
'name' => $this->resultSet->columnName($i),
'table' => null,
'fullname' => $this->resultSet->columnName($i),
'nativetype' => $types[$this->resultSet->columnType($i)],
'nativetype' => $types[$this->resultSet->columnType($i)] ?? null, // buggy in PHP 7.4.4 & 7.3.16, bug 79414
];
}
return $columns;

View File

@@ -39,9 +39,7 @@ class SqlsrvDriver implements Dibi\Driver
private $version = '';
/**
* @throws Dibi\NotSupportedException
*/
/** @throws Dibi\NotSupportedException */
public function __construct(array $config)
{
if (!extension_loaded('sqlsrv')) {
@@ -243,7 +241,7 @@ class SqlsrvDriver implements Dibi\Driver
public function escapeLike(string $value, int $pos): string
{
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
}

View File

@@ -61,7 +61,7 @@ class SqlsrvResult implements Dibi\ResultDriver
*/
public function fetch(bool $assoc): ?array
{
return sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC);
return Dibi\Helpers::false2Null(sqlsrv_fetch_array($this->resultSet, $assoc ? SQLSRV_FETCH_ASSOC : SQLSRV_FETCH_NUMERIC));
}

View File

@@ -423,7 +423,7 @@ class Fluent implements IDataSource
if ($clause === null) {
$data = $this->clauses;
if ($this->command === 'SELECT' && ($data['LIMIT'] || $data['OFFSET'])) {
$args = array_merge(['%lmt %ofs', $data['LIMIT'][0], $data['OFFSET'][0]], $args);
$args = array_merge(['%lmt %ofs', $data['LIMIT'][0] ?? null, $data['OFFSET'][0] ?? null], $args);
unset($data['LIMIT'], $data['OFFSET']);
}

View File

@@ -201,9 +201,7 @@ class Helpers
}
/**
* @internal
*/
/** @internal */
public static function getTypeCache(): HashMap
{
if (self::$types === null) {
@@ -279,18 +277,14 @@ class Helpers
}
/**
* @internal
*/
/** @internal */
public static function false2Null($val)
{
return $val === false ? null : $val;
}
/**
* @internal
*/
/** @internal */
public static function intVal($value): int
{
if (is_int($value)) {

View File

@@ -25,11 +25,15 @@ class FileLogger
/** @var int */
public $filter;
/** @var bool */
private $errorsOnly;
public function __construct(string $file, int $filter = null)
public function __construct(string $file, int $filter = null, bool $errorsOnly = false)
{
$this->file = $file;
$this->filter = $filter ?: Dibi\Event::QUERY;
$this->errorsOnly = $errorsOnly;
}
@@ -38,39 +42,41 @@ class FileLogger
*/
public function logEvent(Dibi\Event $event): void
{
if (($event->type & $this->filter) === 0) {
if (
(($event->type & $this->filter) === 0)
|| ($this->errorsOnly === true && !$event->result instanceof \Exception)
) {
return;
}
$handle = fopen($this->file, 'a');
if (!$handle) {
return; // or throw exception?
}
flock($handle, LOCK_EX);
if ($event->result instanceof \Exception) {
$message = $event->result->getMessage();
if ($code = $event->result->getCode()) {
$message = "[$code] $message";
}
fwrite($handle,
$this->writeToFile(
$event,
"ERROR: $message"
. "\n-- SQL: " . $event->sql
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. ";\n-- " . date('Y-m-d H:i:s')
. "\n\n"
. "\n-- SQL: " . $event->sql
);
} else {
fwrite($handle,
$this->writeToFile(
$event,
'OK: ' . $event->sql
. ($event->count ? ";\n-- rows: " . $event->count : '')
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
. "\n-- source: " . implode(':', $event->source)
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. "\n-- " . date('Y-m-d H:i:s')
. "\n\n"
. ($event->count ? ";\n-- rows: " . $event->count : '')
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
. "\n-- source: " . implode(':', $event->source)
);
}
fclose($handle);
}
private function writeToFile(Dibi\Event $event, string $message): void
{
$message .=
"\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
. "\n-- " . date('Y-m-d H:i:s')
. "\n\n";
file_put_contents($this->file, $message, FILE_APPEND | LOCK_EX);
}
}

View File

@@ -106,18 +106,14 @@ class Column
}
/**
* @return mixed
*/
/** @return mixed */
public function getDefault()
{
return $this->info['default'] ?? null;
}
/**
* @return mixed
*/
/** @return mixed */
public function getVendorInfo(string $key)
{
return $this->info['vendor'][$key] ?? null;

View File

@@ -46,9 +46,7 @@ class Database
}
/**
* @return Table[]
*/
/** @return Table[] */
public function getTables(): array
{
$this->init();
@@ -56,9 +54,7 @@ class Database
}
/**
* @return string[]
*/
/** @return string[] */
public function getTableNames(): array
{
$this->init();

View File

@@ -28,7 +28,7 @@ class Result
/** @var Column[]|null */
private $columns;
/** @var string[]|null */
/** @var Column[]|null */
private $names;
@@ -38,9 +38,7 @@ class Result
}
/**
* @return Column[]
*/
/** @return Column[] */
public function getColumns(): array
{
$this->initColumns();
@@ -48,9 +46,7 @@ class Result
}
/**
* @return string[]
*/
/** @return string[] */
public function getColumnNames(bool $fullNames = false): array
{
$this->initColumns();

View File

@@ -69,9 +69,7 @@ class Table
}
/**
* @return Column[]
*/
/** @return Column[] */
public function getColumns(): array
{
$this->initColumns();
@@ -79,9 +77,7 @@ class Table
}
/**
* @return string[]
*/
/** @return string[] */
public function getColumnNames(): array
{
$this->initColumns();
@@ -113,9 +109,7 @@ class Table
}
/**
* @return ForeignKey[]
*/
/** @return ForeignKey[] */
public function getForeignKeys(): array
{
$this->initForeignKeys();
@@ -123,9 +117,7 @@ class Table
}
/**
* @return Index[]
*/
/** @return Index[] */
public function getIndexes(): array
{
$this->initIndexes();

View File

@@ -242,6 +242,9 @@ class Result implements IDataSource
$data = null;
$assoc = preg_split('#(\[\]|->|=|\|)#', $assoc, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if (!$assoc) {
throw new \InvalidArgumentException("Invalid descriptor '$assoc'.");
}
// check columns
foreach ($assoc as $as) {
@@ -282,7 +285,7 @@ class Result implements IDataSource
}
} elseif ($as !== '|') { // associative-array node
$x = &$x[$row->$as];
$x = &$x[(string) $row->$as];
}
}
@@ -296,9 +299,7 @@ class Result implements IDataSource
}
/**
* @deprecated
*/
/** @deprecated */
private function oldFetchAssoc(string $assoc)
{
$this->seek(0);
@@ -350,7 +351,7 @@ class Result implements IDataSource
}
} else { // associative-array node
$x = &$x[$row->$as];
$x = &$x[(string) $row->$as];
}
}
@@ -452,6 +453,7 @@ class Result implements IDataSource
continue;
}
$value = $row[$key];
if ($type === Type::TEXT) {
$row[$key] = (string) $value;
@@ -501,6 +503,12 @@ class Result implements IDataSource
} else {
$row[$key] = json_decode($value, $this->formats[$type] === 'array');
}
} elseif ($type === null) {
$row[$key] = $value;
} else {
throw new \RuntimeException('Unexpected type ' . $type);
}
}
}
@@ -569,9 +577,7 @@ class Result implements IDataSource
}
/**
* @return Reflection\Column[]
*/
/** @return Reflection\Column[] */
final public function getColumns(): array
{
return $this->getInfo()->getColumns();

View File

@@ -415,12 +415,15 @@ final class Translator
return (string) $value;
case 'like~': // LIKE string%
return $this->driver->escapeLike($value, 1);
return $this->driver->escapeLike($value, 2);
case '~like': // LIKE %string
return $this->driver->escapeLike($value, -1);
return $this->driver->escapeLike($value, 1);
case '~like~': // LIKE %string%
return $this->driver->escapeLike($value, 3);
case 'like': // LIKE string
return $this->driver->escapeLike($value, 0);
case 'and':

View File

@@ -44,7 +44,7 @@ class dibi
/** version */
public const
VERSION = '4.1.0';
VERSION = '4.1.3';
/** sorting order */
public const

View File

@@ -52,6 +52,17 @@ test(function () use ($config) {
});
test(function () use ($config) {
$conn = new Connection($config);
Assert::equal('hello', $conn->query('SELECT %s', 'hello')->fetchSingle());
$conn->disconnect();
$conn->connect();
Assert::equal('hello', $conn->query('SELECT %s', 'hello')->fetchSingle());
});
test(function () use ($config) {
Assert::exception(function () use ($config) {
new Connection($config + ['onConnect' => '']);

View File

@@ -71,3 +71,9 @@ Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'baa', 'aa'));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'aab', 'aa'));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like~', 'bba', '%a'));
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'b%a', '%a'));
// matches
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'a'));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'aa'));
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %like', 'a', 'b'));

4
tests/phpstan.neon Normal file
View File

@@ -0,0 +1,4 @@
parameters:
ignoreErrors:
# The namespace is referenced, not the class.
- '#Class dibi referenced with incorrect case: Dibi#'