1
0
mirror of https://github.com/dg/dibi.git synced 2025-09-01 18:12:51 +02:00

Compare commits

..

11 Commits

Author SHA1 Message Date
David Grudl
34bc742245 refactoring 2020-10-08 16:49:47 +02:00
Miloslav Hůla
f5fa2255ff FileLogger: fixed object to string conversion with custom driver (#376) (#376)
Co-authored-by: Miloslav Hůla <miloslav.hula@fsv.cvut.cz>
2020-10-08 16:38:35 +02:00
Miloslav Hůla
7b02296f3e Tracy\Panel: fixed object to string converion error with custom driver (#373)
Co-authored-by: Miloslav Hůla <miloslav.hula@fsv.cvut.cz>
2020-10-08 16:38:35 +02:00
David Grudl
df4cddac1f Tracy\Panel: supports multiple connections [Closes #365]
Partially reverts "Tracy\Panel: one panel is used per connection"

This reverts commit ae6c8756b6.
2020-10-08 16:38:35 +02:00
groupnet
cc37121390 Postgre driver - add connect_type config parameter (#370)
- adds the option to pass the connect_type as config parameter
 - PHP default is 0, but to make this change non-breaking defauls to PGSQL_CONNECT_FORCE_NEW
 - see PHP docs: https://www.php.net/manual/en/function.pg-connect.php
2020-10-08 15:55:11 +02:00
LHavlicek
a95b409231 MySqliDriver: fixed DateInterval encoding (#371) 2020-10-08 15:55:11 +02:00
Jakub Bouček
3b057c2e35 MySqliDriver: added support for ping (#372) 2020-10-08 15:55:11 +02:00
David Grudl
f444b5d993 typo 2020-10-08 15:55:11 +02:00
David Grudl
6e41c4223b tests: test() with description 2020-10-08 15:55:11 +02:00
David Grudl
0ee4628712 SqlsrvDriver: improved escapeBinary [Closes #287] 2020-10-07 03:19:03 +02:00
David Grudl
ab3677203c added funding.yml 2020-10-07 03:19:03 +02:00
15 changed files with 130 additions and 69 deletions

1
.github/funding.yml vendored Normal file
View File

@@ -0,0 +1 @@
github: dg

View File

@@ -16,6 +16,7 @@
"require-dev": {
"tracy/tracy": "~2.2",
"nette/tester": "~2.0",
"nette/di": "^3.0",
"phpstan/phpstan": "^0.12"
},
"replace": {

View File

@@ -14,7 +14,13 @@ Introduction
Database access functions in PHP are not standardised. This library
hides the differences between them, and above all, it gives you a very handy interface.
If you like Dibi, **[please make a donation now](https://nette.org/make-donation?to=dibi)**. Thank you!
Support Project
---------------
Do you like Dibi? Are you looking forward to the new features?
[![Donate](https://files.nette.org/icons/donation-1.svg?)](https://nette.org/make-donation?to=dibi)
Installation
@@ -42,11 +48,11 @@ The database connection is represented by the object `Dibi\Connection`:
```php
$database = new Dibi\Connection([
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'table',
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'table',
]);
$result = $database->query('SELECT * FROM users');
@@ -56,12 +62,12 @@ Alternatively, you can use the `dibi` static register, which maintains a connect
```php
dibi::connect([
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
'driver' => 'mysqli',
'host' => 'localhost',
'username' => 'root',
'password' => '***',
'database' => 'test',
'charset' => 'utf8',
]);
$result = dibi::query('SELECT * FROM users');
@@ -229,8 +235,8 @@ Example:
```php
$arr = [
'a' => 'hello',
'b' => true,
'a' => 'hello',
'b' => true,
];
$database->query('INSERT INTO table %v', $arr);
@@ -502,7 +508,7 @@ $all = $result->fetchAssoc('customer_id|order_id');
// we will iterate like this:
foreach ($all as $customerId => $orders) {
foreach ($orders as $orderId => $order) {
...
...
}
}
```
@@ -534,7 +540,7 @@ $all = $result->fetchAssoc('name[]order_id');
// we get all the Arnolds in the results
foreach ($all['Arnold Rimmer'] as $arnoldOrders) {
foreach ($arnoldOrders as $orderId => $order) {
...
...
}
}
```
@@ -548,8 +554,8 @@ foreach ($all as $customerId => $orders) {
echo "Customer $customerId":
foreach ($orders as $orderId => $order) {
echo "ID number: $order->number";
// customer name is in $order->name
echo "ID number: $order->number";
// customer name is in $order->name
}
}
```
@@ -571,7 +577,7 @@ foreach ($all as $customerId => $row) {
echo "Customer $row->name":
foreach ($row->order_id as $orderId => $order) {
echo "ID number: $order->number";
echo "ID number: $order->number";
}
}
```

View File

@@ -105,6 +105,15 @@ class Panel implements Tracy\IBarPanel
}
$totalTime = $s = null;
$singleConnection = reset($this->events)->connection;
foreach ($this->events as $event) {
if ($event->connection !== $singleConnection) {
$singleConnection = null;
break;
}
}
foreach ($this->events as $event) {
$totalTime += $event->time;
$connection = $event->connection;
@@ -135,7 +144,10 @@ class Panel implements Tracy\IBarPanel
$s .= Tracy\Helpers::editorLink($event->source[0], $event->source[1]);//->class('tracy-DibiProfiler-source');
}
$s .= "</td><td>{$event->count}</td></tr>";
$s .= "</td><td>{$event->count}</td>";
if (!$singleConnection) {
$s .= '<td>' . htmlspecialchars($this->getConnectionName($connection)) . '</td></tr>';
}
}
return '<style> #tracy-debug td.tracy-DibiProfiler-sql { background: white !important }
@@ -143,12 +155,21 @@ class Panel implements Tracy\IBarPanel
#tracy-debug tracy-DibiProfiler tr table { margin: 8px 0; max-height: 150px; overflow:auto } </style>
<h1>Queries: ' . count($this->events)
. ($totalTime === null ? '' : ', time: ' . number_format($totalTime * 1000, 1, '.', '') . 'ms') . ', '
. htmlspecialchars($connection->getConfig('driver') . ($connection->getConfig('name') ? '/' . $connection->getConfig('name') : '')
. ($connection->getConfig('host') ? '@' . $connection->getConfig('host') : '')) . '</h1>
. htmlspecialchars($this->getConnectionName($singleConnection)) . '</h1>
<div class="tracy-inner tracy-DibiProfiler">
<table>
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th></tr>' . $s . '
<tr><th>Time&nbsp;ms</th><th>SQL Statement</th><th>Rows</th>' . (!$singleConnection ? '<th>Connection</th>' : '') . '</tr>
' . $s . '
</table>
</div>';
}
private function getConnectionName(Dibi\Connection $connection): string
{
$driver = $connection->getConfig('driver');
return (is_object($driver) ? get_class($driver) : $driver)
. ($connection->getConfig('name') ? '/' . $connection->getConfig('name') : '')
. ($connection->getConfig('host') ? '@' . $connection->getConfig('host') : '');
}
}

View File

@@ -130,6 +130,15 @@ class MySqliDriver implements Dibi\Driver
}
/**
* Pings a server connection, or tries to reconnect if the connection has gone down.
*/
public function ping(): bool
{
return $this->connection->ping();
}
/**
* Executes the SQL query.
* @throws Dibi\DriverException
@@ -148,6 +157,9 @@ class MySqliDriver implements Dibi\Driver
}
/**
* @param int|string $code
*/
public static function createException(string $message, $code, string $sql): Dibi\DriverException
{
if (in_array($code, [1216, 1217, 1451, 1452, 1701], true)) {
@@ -305,7 +317,7 @@ class MySqliDriver implements Dibi\Driver
if ($value->y || $value->m || $value->d) {
throw new Dibi\NotSupportedException('Only time interval is supported.');
}
return $value->format('%r%H:%I:%S.%f');
return $value->format("'%r%H:%I:%S.%f'");
}

View File

@@ -23,6 +23,7 @@ use Dibi\Helpers;
* - charset => character encoding to set (default is utf8)
* - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource
* - connect_type (int) => see pg_connect()
*/
class PostgreDriver implements Dibi\Driver
{
@@ -62,14 +63,15 @@ class PostgreDriver implements Dibi\Driver
}
}
}
$connectType = $config['connect_type'] ?? PGSQL_CONNECT_FORCE_NEW;
set_error_handler(function (int $severity, string $message) use (&$error) {
$error = $message;
});
if (empty($config['persistent'])) {
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
$this->connection = pg_connect($string, $connectType);
} else {
$this->connection = pg_pconnect($string);
$this->connection = pg_pconnect($string, $connectType);
}
restore_error_handler();
}

View File

@@ -200,7 +200,7 @@ class SqlsrvDriver implements Dibi\Driver
public function escapeBinary(string $value): string
{
return "'" . str_replace("'", "''", $value) . "'";
return '0x' . bin2hex($value);
}

View File

@@ -32,6 +32,12 @@ namespace Dibi;
* @method Fluent and(...$cond)
* @method Fluent or(...$cond)
* @method Fluent using(...$cond)
* @method Fluent update(...$cond)
* @method Fluent insert(...$cond)
* @method Fluent delete(...$cond)
* @method Fluent into(...$cond)
* @method Fluent values(...$cond)
* @method Fluent set(...$args)
* @method Fluent asc()
* @method Fluent desc()
*/

View File

@@ -73,8 +73,9 @@ class FileLogger
private function writeToFile(Dibi\Event $event, string $message): void
{
$driver = $event->connection->getConfig('driver');
$message .=
"\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
"\n-- driver: " . (is_object($driver) ? get_class($driver) : $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

@@ -19,7 +19,7 @@ class Result implements IDataSource
{
use Strict;
/** @var ResultDriver */
/** @var ResultDriver|null */
private $driver;
/** @var array Translate table */
@@ -295,6 +295,7 @@ class Result implements IDataSource
} while ($row = $this->fetch());
unset($x);
/** @var mixed[] $data */
return $data;
}

View File

@@ -92,24 +92,25 @@ final class Translator
$sql[] = $arg;
} else {
$sql[] = substr($arg, 0, $toSkip)
/*
. preg_replace_callback('/
(?=[`[\'":%?]) ## speed-up
(?:
`(.+?)`| ## 1) `identifier`
\[(.+?)\]| ## 2) [identifier]
(\')((?:\'\'|[^\'])*)\'| ## 3,4) 'string'
(")((?:""|[^"])*)"| ## 5,6) "string"
(\'|")| ## 7) lone quote
:(\S*?:)([a-zA-Z0-9._]?)| ## 8,9) :substitution:
%([a-zA-Z~][a-zA-Z0-9~]{0,5})|## 10) modifier
(\?) ## 11) placeholder
)/xs',
*/ // note: this can change $this->args & $this->cursor & ...
. preg_replace_callback('/(?=[`[\'":%?])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?)|%([a-zA-Z~][a-zA-Z0-9~]{0,5})|(\?))/s',
// note: this can change $this->args & $this->cursor & ...
. preg_replace_callback(<<<'XX'
/
(?=[`['":%?]) ## speed-up
(?:
`(.+?)`| ## 1) `identifier`
\[(.+?)\]| ## 2) [identifier]
(')((?:''|[^'])*)'| ## 3,4) string
(")((?:""|[^"])*)"| ## 5,6) "string"
('|")| ## 7) lone quote
:(\S*?:)([a-zA-Z0-9._]?)| ## 8,9) :substitution:
%([a-zA-Z~][a-zA-Z0-9~]{0,5})| ## 10) modifier
(\?) ## 11) placeholder
)/xs
XX
,
[$this, 'cb'],
substr($arg, $toSkip)
);
);
if (preg_last_error()) {
throw new PcreException;
}
@@ -400,11 +401,22 @@ final class Translator
$toSkip = strcspn($value, '`[\'":');
if (strlen($value) !== $toSkip) {
$value = substr($value, 0, $toSkip)
. preg_replace_callback(
'/(?=[`[\'":])(?:`(.+?)`|\[(.+?)\]|(\')((?:\'\'|[^\'])*)\'|(")((?:""|[^"])*)"|(\'|")|:(\S*?:)([a-zA-Z0-9._]?))/s',
[$this, 'cb'],
substr($value, $toSkip)
);
. preg_replace_callback(<<<'XX'
/
(?=[`['":])
(?:
`(.+?)`|
\[(.+?)\]|
(')((?:''|[^'])*)'|
(")((?:""|[^"])*)"|
('|")|
:(\S*?:)([a-zA-Z0-9._]?)
)/sx
XX
,
[$this, 'cb'],
substr($value, $toSkip)
);
if (preg_last_error()) {
throw new PcreException;
}

View File

@@ -12,7 +12,7 @@ use Tester\Assert;
require __DIR__ . '/bootstrap.php';
test(function () use ($config) {
test('', function () use ($config) {
$conn = new Connection($config);
Assert::true($conn->isConnected());
@@ -21,7 +21,7 @@ test(function () use ($config) {
});
test(function () use ($config) { // lazy
test('lazy', function () use ($config) {
$conn = new Connection($config + ['lazy' => true]);
Assert::false($conn->isConnected());
@@ -30,7 +30,7 @@ test(function () use ($config) { // lazy
});
test(function () use ($config) {
test('', function () use ($config) {
$conn = new Connection($config);
Assert::true($conn->isConnected());
@@ -40,7 +40,7 @@ test(function () use ($config) {
});
test(function () use ($config) {
test('', function () use ($config) {
$conn = new Connection($config);
Assert::true($conn->isConnected());
@@ -52,7 +52,7 @@ test(function () use ($config) {
});
test(function () use ($config) {
test('', function () use ($config) {
$conn = new Connection($config);
Assert::equal('hello', $conn->query('SELECT %s', 'hello')->fetchSingle());
@@ -63,7 +63,7 @@ test(function () use ($config) {
});
test(function () use ($config) {
test('', function () use ($config) {
Assert::exception(function () use ($config) {
new Connection($config + ['onConnect' => '']);
}, InvalidArgumentException::class, "Configuration option 'onConnect' must be array.");

View File

@@ -29,13 +29,11 @@ Assert::exception(function () {
}, Dibi\DriverException::class, 'PDO connection in exception or warning error mode is not supported.');
// PDO error mode: explicitly set silent
test(function () {
test('PDO error mode: explicitly set silent', function () {
buildPdoDriver(PDO::ERRMODE_SILENT);
});
// PDO error mode: implicitly set silent
test(function () {
test('PDO error mode: implicitly set silent', function () {
buildPdoDriver(null);
});

View File

@@ -24,7 +24,7 @@ class MockResult extends Dibi\Result
}
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::BOOL);
@@ -46,7 +46,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::TEXT);
@@ -62,7 +62,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::FLOAT);
@@ -139,7 +139,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::INTEGER);
@@ -165,7 +165,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::DATETIME);
@@ -183,7 +183,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::DATETIME);
$result->setFormat(Type::DATETIME, 'Y-m-d H:i:s');
@@ -202,7 +202,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::DATE);
@@ -218,7 +218,7 @@ test(function () {
});
test(function () {
test('', function () {
$result = new MockResult;
$result->setType('col', Type::TIME);

View File

@@ -37,7 +37,7 @@ if ($config['system'] === 'odbc') {
}
function test(Closure $function)
function test(string $title, Closure $function): void
{
$function();
}