mirror of
https://github.com/dg/dibi.git
synced 2025-08-31 17:51:43 +02:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ed2a827419 | ||
|
e46be6cee6 | ||
|
0f69d5d32c | ||
|
e826e3a719 | ||
|
6eac117f5f | ||
|
2a2c814b0a | ||
|
dfab3d711c | ||
|
34e16031f7 | ||
|
73160e9418 | ||
|
f18056a066 | ||
|
0bd222b3f1 | ||
|
9f71f39470 | ||
|
0b0d805040 | ||
|
8c761eac5c | ||
|
2f857c28d6 | ||
|
efe1cbdc20 | ||
|
21dad1d846 | ||
|
7d55fd03b0 | ||
|
294787a26e | ||
|
9d4bef53d3 | ||
|
1db63d81e9 | ||
|
c7dee4d822 | ||
|
f2927a1b08 | ||
|
b5a66fdb26 | ||
|
c38f6991b0 | ||
|
faab306418 | ||
|
74ba6cfd34 | ||
|
f46b7f4d79 | ||
|
c1640c5e7b | ||
|
a2afac80f2 | ||
|
0535d57e6b | ||
|
369768a62a | ||
|
78d6603bb0 | ||
|
7f22279333 | ||
|
e66cb84cb5 | ||
|
5ab8afc704 | ||
|
219882a962 | ||
|
7e127f5914 |
15
.travis.yml
15
.travis.yml
@@ -3,6 +3,11 @@ php:
|
|||||||
- 7.1
|
- 7.1
|
||||||
- 7.2
|
- 7.2
|
||||||
- 7.3
|
- 7.3
|
||||||
|
- 7.4
|
||||||
|
|
||||||
|
services:
|
||||||
|
- mysql
|
||||||
|
- postgresql
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
# turn off XDebug
|
# turn off XDebug
|
||||||
@@ -27,6 +32,7 @@ after_failure:
|
|||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- name: Nette Code Checker
|
- name: Nette Code Checker
|
||||||
|
php: 7.4
|
||||||
install:
|
install:
|
||||||
- travis_retry composer create-project nette/code-checker temp/code-checker ^3 --no-progress
|
- travis_retry composer create-project nette/code-checker temp/code-checker ^3 --no-progress
|
||||||
script:
|
script:
|
||||||
@@ -34,6 +40,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- name: Nette Coding Standard
|
- name: Nette Coding Standard
|
||||||
|
php: 7.4
|
||||||
install:
|
install:
|
||||||
- travis_retry composer create-project nette/coding-standard temp/coding-standard ^2 --no-progress
|
- travis_retry composer create-project nette/coding-standard temp/coding-standard ^2 --no-progress
|
||||||
script:
|
script:
|
||||||
@@ -41,15 +48,13 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- stage: Static Analysis (informative)
|
- stage: Static Analysis (informative)
|
||||||
install:
|
php: 7.4
|
||||||
# Install PHPStan
|
|
||||||
- travis_retry composer create-project phpstan/phpstan-shim temp/phpstan --no-progress
|
|
||||||
- travis_retry composer install --no-progress --prefer-dist
|
|
||||||
script:
|
script:
|
||||||
- php temp/phpstan/phpstan.phar analyse --autoload-file vendor/autoload.php --level 5 src
|
- composer run-script phpstan
|
||||||
|
|
||||||
|
|
||||||
- stage: Code Coverage
|
- stage: Code Coverage
|
||||||
|
php: 7.4
|
||||||
script:
|
script:
|
||||||
- vendor/bin/tester -p phpdbg tests -s --coverage ./coverage.xml --coverage-src ./src
|
- vendor/bin/tester -p phpdbg tests -s --coverage ./coverage.xml --coverage-src ./src
|
||||||
after_script:
|
after_script:
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"description": "Dibi is Database Abstraction Library for PHP",
|
"description": "Dibi is Database Abstraction Library for PHP",
|
||||||
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "sqlsrv", "oracle", "access", "pdo", "odbc"],
|
"keywords": ["database", "dbal", "mysql", "postgresql", "sqlite", "mssql", "sqlsrv", "oracle", "access", "pdo", "odbc"],
|
||||||
"homepage": "https://dibiphp.com",
|
"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": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "David Grudl",
|
"name": "David Grudl",
|
||||||
@@ -15,7 +15,8 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"tracy/tracy": "~2.2",
|
"tracy/tracy": "~2.2",
|
||||||
"nette/tester": "~2.0"
|
"nette/tester": "~2.0",
|
||||||
|
"phpstan/phpstan": "^0.12"
|
||||||
},
|
},
|
||||||
"replace": {
|
"replace": {
|
||||||
"dg/dibi": "*"
|
"dg/dibi": "*"
|
||||||
@@ -23,9 +24,13 @@
|
|||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": ["src/"]
|
"classmap": ["src/"]
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"phpstan": "phpstan analyse --autoload-file vendor/autoload.php --level 5 --configuration tests/phpstan.neon src",
|
||||||
|
"tester": "tester tests -s"
|
||||||
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "4.0-dev"
|
"dev-master": "4.1-dev"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ $dibi = new Dibi\Connection([
|
|||||||
// enable query logging to this file
|
// enable query logging to this file
|
||||||
'profiler' => [
|
'profiler' => [
|
||||||
'file' => 'log/log.sql',
|
'file' => 'log/log.sql',
|
||||||
|
'errorsOnly' => false,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
12
readme.md
12
readme.md
@@ -26,7 +26,7 @@ Install Dibi via Composer:
|
|||||||
composer require dibi/dibi
|
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
|
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`.
|
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
|
```php
|
||||||
$result = $database->query('SELECT * FROM users');
|
$result = $database->query('SELECT * FROM users');
|
||||||
|
|
||||||
@@ -110,7 +112,7 @@ $ids = [10, 20, 30];
|
|||||||
$result = $database->query('SELECT * FROM users WHERE id IN (?)', $ids);
|
$result = $database->query('SELECT * FROM users WHERE id IN (?)', $ids);
|
||||||
```
|
```
|
||||||
|
|
||||||
**WARNING, never concencate parameters to SQL, the vulnerability would arise [SQL injection](https://en.wikipedia.org/wiki/SQL_injection)**
|
**WARNING: Never concatenate parameters to SQL. It would create a [SQL injection](https://en.wikipedia.org/wiki/SQL_injection)** vulnerability.
|
||||||
```
|
```
|
||||||
$result = $database->query('SELECT * FROM users WHERE id = ' . $id); // BAD!!!
|
$result = $database->query('SELECT * FROM users WHERE id = ' . $id); // BAD!!!
|
||||||
```
|
```
|
||||||
@@ -147,7 +149,7 @@ $name = $database->fetchSingle('SELECT name FROM users WHERE id = ?', $id);
|
|||||||
|
|
||||||
### Modifiers
|
### Modifiers
|
||||||
|
|
||||||
In addition to the `?` wild char, we can also use modifiers:
|
In addition to the `?` wildcard char, we can also use modifiers:
|
||||||
|
|
||||||
| modifier | description
|
| modifier | description
|
||||||
|----------|-----
|
|----------|-----
|
||||||
@@ -161,6 +163,7 @@ In addition to the `?` wild char, we can also use modifiers:
|
|||||||
| %d | date (accepts DateTime, string or UNIX timestamp)
|
| %d | date (accepts DateTime, string or UNIX timestamp)
|
||||||
| %dt | datetime (accepts DateTime, string or UNIX timestamp)
|
| %dt | datetime (accepts DateTime, string or UNIX timestamp)
|
||||||
| %n | identifier, ie the name of the table or column
|
| %n | identifier, ie the name of the table or column
|
||||||
|
| %N | identifier, treats period as a common character, ie alias or a database name (`%n AS %N` or `DROP DATABASE %N`)
|
||||||
| %SQL | SQL - directly inserts into SQL (the alternative is Dibi\Literal)
|
| %SQL | SQL - directly inserts into SQL (the alternative is Dibi\Literal)
|
||||||
| %ex | SQL expression or array of expressions
|
| %ex | SQL expression or array of expressions
|
||||||
| %lmt | special - adds LIMIT to the query
|
| %lmt | special - adds LIMIT to the query
|
||||||
@@ -182,7 +185,7 @@ $result = $database->query('SELECT * FROM users WHERE id IN (%i)', $ids);
|
|||||||
// SELECT * FROM users WHERE id IN (10, 20, 30)
|
// 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
|
```php
|
||||||
$table = 'blog.users';
|
$table = 'blog.users';
|
||||||
@@ -198,6 +201,7 @@ Three special modifiers are available for LIKE:
|
|||||||
| `%like~` | the expression starts with a string
|
| `%like~` | the expression starts with a string
|
||||||
| `%~like` | the expression ends with a string
|
| `%~like` | the expression ends with a string
|
||||||
| `%~like~` | the expression contains a string
|
| `%~like~` | the expression contains a string
|
||||||
|
| `%like` | the expression matches a string
|
||||||
|
|
||||||
Search for names beginning with a string:
|
Search for names beginning with a string:
|
||||||
|
|
||||||
|
@@ -43,32 +43,21 @@ class Connection implements IConnection
|
|||||||
* - lazy (bool) => if true, connection will be established only when required
|
* - lazy (bool) => if true, connection will be established only when required
|
||||||
* - result (array) => result set options
|
* - result (array) => result set options
|
||||||
* - formatDateTime => date-time format (if empty, DateTime objects will be returned)
|
* - formatDateTime => date-time format (if empty, DateTime objects will be returned)
|
||||||
|
* - formatJson => json format (
|
||||||
|
* "string" for leaving value as is,
|
||||||
|
* "object" for decoding json as \stdClass,
|
||||||
|
* "array" for decoding json as an array - default
|
||||||
|
* )
|
||||||
* - profiler (array)
|
* - profiler (array)
|
||||||
* - run (bool) => enable profiler?
|
* - run (bool) => enable profiler?
|
||||||
* - file => file to log
|
* - file => file to log
|
||||||
|
* - errorsOnly (bool) => log only errors
|
||||||
* - substitutes (array) => map of driver specific substitutes (under development)
|
* - substitutes (array) => map of driver specific substitutes (under development)
|
||||||
* - onConnect (array) => list of SQL queries to execute (by Connection::query()) after connection is established
|
* - onConnect (array) => list of SQL queries to execute (by Connection::query()) after connection is established
|
||||||
* @param array $config connection parameters
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($config, string $name = null)
|
public function __construct(array $config, string $name = null)
|
||||||
{
|
{
|
||||||
if (is_string($config)) {
|
|
||||||
trigger_error(__METHOD__ . '() Configuration should be array.', E_USER_DEPRECATED);
|
|
||||||
parse_str($config, $config);
|
|
||||||
|
|
||||||
} elseif ($config instanceof Traversable) {
|
|
||||||
trigger_error(__METHOD__ . '() Configuration should be array.', E_USER_DEPRECATED);
|
|
||||||
$tmp = [];
|
|
||||||
foreach ($config as $key => $val) {
|
|
||||||
$tmp[$key] = $val instanceof Traversable ? iterator_to_array($val) : $val;
|
|
||||||
}
|
|
||||||
$config = $tmp;
|
|
||||||
|
|
||||||
} elseif (!is_array($config)) {
|
|
||||||
throw new \InvalidArgumentException('Configuration must be array.');
|
|
||||||
}
|
|
||||||
|
|
||||||
Helpers::alias($config, 'username', 'user');
|
Helpers::alias($config, 'username', 'user');
|
||||||
Helpers::alias($config, 'password', 'pass');
|
Helpers::alias($config, 'password', 'pass');
|
||||||
Helpers::alias($config, 'host', 'hostname');
|
Helpers::alias($config, 'host', 'hostname');
|
||||||
@@ -76,12 +65,14 @@ class Connection implements IConnection
|
|||||||
Helpers::alias($config, 'result|formatDateTime', 'resultDateTime');
|
Helpers::alias($config, 'result|formatDateTime', 'resultDateTime');
|
||||||
$config['driver'] = $config['driver'] ?? 'mysqli';
|
$config['driver'] = $config['driver'] ?? 'mysqli';
|
||||||
$config['name'] = $name;
|
$config['name'] = $name;
|
||||||
|
$config['result']['formatJson'] = $config['result']['formatJson'] ?? 'array';
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
|
||||||
// profiler
|
// profiler
|
||||||
if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
|
if (isset($config['profiler']['file']) && (!isset($config['profiler']['run']) || $config['profiler']['run'])) {
|
||||||
$filter = $config['profiler']['filter'] ?? Event::QUERY;
|
$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:"; });
|
$this->substitutes = new HashMap(function (string $expr) { return ":$expr:"; });
|
||||||
@@ -119,6 +110,7 @@ class Connection implements IConnection
|
|||||||
{
|
{
|
||||||
if ($this->config['driver'] instanceof Driver) {
|
if ($this->config['driver'] instanceof Driver) {
|
||||||
$this->driver = $this->config['driver'];
|
$this->driver = $this->config['driver'];
|
||||||
|
$this->translator = new Translator($this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} elseif (is_subclass_of($this->config['driver'], Driver::class)) {
|
} elseif (is_subclass_of($this->config['driver'], Driver::class)) {
|
||||||
@@ -135,6 +127,8 @@ class Connection implements IConnection
|
|||||||
$event = $this->onEvent ? new Event($this, Event::CONNECT) : null;
|
$event = $this->onEvent ? new Event($this, Event::CONNECT) : null;
|
||||||
try {
|
try {
|
||||||
$this->driver = new $class($this->config);
|
$this->driver = new $class($this->config);
|
||||||
|
$this->translator = new Translator($this);
|
||||||
|
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$this->onEvent($event->done());
|
$this->onEvent($event->done());
|
||||||
}
|
}
|
||||||
@@ -160,7 +154,7 @@ class Connection implements IConnection
|
|||||||
{
|
{
|
||||||
if ($this->driver) {
|
if ($this->driver) {
|
||||||
$this->driver->disconnect();
|
$this->driver->disconnect();
|
||||||
$this->driver = null;
|
$this->driver = $this->translator = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,11 +255,7 @@ class Connection implements IConnection
|
|||||||
if (!$this->driver) {
|
if (!$this->driver) {
|
||||||
$this->connect();
|
$this->connect();
|
||||||
}
|
}
|
||||||
if (!$this->translator) {
|
return (clone $this->translator)->translate($args);
|
||||||
$this->translator = new Translator($this);
|
|
||||||
}
|
|
||||||
$translator = clone $this->translator;
|
|
||||||
return $translator->translate($args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,16 +306,6 @@ class Connection implements IConnection
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public function affectedRows(): int
|
|
||||||
{
|
|
||||||
trigger_error(__METHOD__ . '() is deprecated, use getAffectedRows()', E_USER_DEPRECATED);
|
|
||||||
return $this->getAffectedRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
@@ -336,23 +316,13 @@ class Connection implements IConnection
|
|||||||
$this->connect();
|
$this->connect();
|
||||||
}
|
}
|
||||||
$id = $this->driver->getInsertId($sequence);
|
$id = $this->driver->getInsertId($sequence);
|
||||||
if ($id < 1) {
|
if ($id === null) {
|
||||||
throw new Exception('Cannot retrieve last generated ID.');
|
throw new Exception('Cannot retrieve last generated ID.');
|
||||||
}
|
}
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public function insertId(string $sequence = null): int
|
|
||||||
{
|
|
||||||
trigger_error(__METHOD__ . '() is deprecated, use getInsertId()', E_USER_DEPRECATED);
|
|
||||||
return $this->getInsertId($sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begins a transaction (if supported).
|
* Begins a transaction (if supported).
|
||||||
*/
|
*/
|
||||||
@@ -432,7 +402,8 @@ class Connection implements IConnection
|
|||||||
{
|
{
|
||||||
$res = new Result($resultDriver);
|
$res = new Result($resultDriver);
|
||||||
return $res->setFormat(Type::DATE, $this->config['result']['formatDate'])
|
return $res->setFormat(Type::DATE, $this->config['result']['formatDate'])
|
||||||
->setFormat(Type::DATETIME, $this->config['result']['formatDateTime']);
|
->setFormat(Type::DATETIME, $this->config['result']['formatDateTime'])
|
||||||
|
->setFormat(Type::JSON, $this->config['result']['formatJson']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -32,77 +32,8 @@ class DateTime extends \DateTimeImmutable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @deprecated use modify() */
|
|
||||||
public function modifyClone(string $modify = ''): self
|
|
||||||
{
|
|
||||||
trigger_error(__METHOD__ . '() is deprecated, use modify()', E_USER_DEPRECATED);
|
|
||||||
$dolly = clone $this;
|
|
||||||
return $modify ? $dolly->modify($modify) : $dolly;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
return $this->format('Y-m-d H:i:s.u');
|
return $this->format('Y-m-d H:i:s.u');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/********************* immutable usage detector ****************d*g**/
|
|
||||||
|
|
||||||
|
|
||||||
public function __destruct()
|
|
||||||
{
|
|
||||||
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
|
|
||||||
if (isset($trace[0]['file'], $trace[1]['function']) && $trace[0]['file'] === __FILE__ && $trace[1]['function'] !== '__construct') {
|
|
||||||
trigger_error(__CLASS__ . ' is immutable now, check how it is used in ' . $trace[1]['file'] . ':' . $trace[1]['line'], E_USER_WARNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function add($interval)
|
|
||||||
{
|
|
||||||
return parent::add($interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function modify($modify)
|
|
||||||
{
|
|
||||||
return parent::modify($modify);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setDate($year, $month, $day)
|
|
||||||
{
|
|
||||||
return parent::setDate($year, $month, $day);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setISODate($year, $week, $day = 1)
|
|
||||||
{
|
|
||||||
return parent::setISODate($year, $week, $day);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setTime($hour, $minute, $second = 0, $micro = 0)
|
|
||||||
{
|
|
||||||
return parent::setTime($hour, $minute, $second, $micro);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setTimestamp($unixtimestamp)
|
|
||||||
{
|
|
||||||
return parent::setTimestamp($unixtimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setTimezone($timezone)
|
|
||||||
{
|
|
||||||
return parent::setTimezone($timezone);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function sub($interval)
|
|
||||||
{
|
|
||||||
return parent::sub($interval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
219
src/Dibi/Drivers/DummyDriver.php
Normal file
219
src/Dibi/Drivers/DummyDriver.php
Normal 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 [];
|
||||||
|
}
|
||||||
|
}
|
@@ -40,9 +40,7 @@ class FirebirdDriver implements Dibi\Driver
|
|||||||
private $inTransaction = false;
|
private $inTransaction = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('interbase')) {
|
if (!extension_loaded('interbase')) {
|
||||||
@@ -247,37 +245,31 @@ class FirebirdDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d'");
|
return $value->format("'Y-m-d'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return "'" . substr($value->format('Y-m-d H:i:s.u'), 0, -2) . "'";
|
return "'" . substr($value->format('Y-m-d H:i:s.u'), 0, -2) . "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
throw new Dibi\NotImplementedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
public function escapeLike(string $value, int $pos): string
|
public function escapeLike(string $value, int $pos): string
|
||||||
{
|
{
|
||||||
$value = addcslashes($this->escapeText($value), '%_\\');
|
$value = addcslashes($this->escapeText($value), '%_\\');
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -47,9 +47,7 @@ class MySqliDriver implements Dibi\Driver
|
|||||||
private $buffered;
|
private $buffered;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('mysqli')) {
|
if (!extension_loaded('mysqli')) {
|
||||||
@@ -93,7 +91,7 @@ class MySqliDriver implements Dibi\Driver
|
|||||||
@$this->connection->real_connect( // intentionally @
|
@$this->connection->real_connect( // intentionally @
|
||||||
(empty($config['persistent']) ? '' : 'p:') . $config['host'],
|
(empty($config['persistent']) ? '' : 'p:') . $config['host'],
|
||||||
$config['username'],
|
$config['username'],
|
||||||
$config['password'],
|
$config['password'] ?? '',
|
||||||
$config['database'] ?? '',
|
$config['database'] ?? '',
|
||||||
$config['port'] ?? 0,
|
$config['port'] ?? 0,
|
||||||
$config['socket'],
|
$config['socket'],
|
||||||
@@ -199,7 +197,7 @@ class MySqliDriver implements Dibi\Driver
|
|||||||
*/
|
*/
|
||||||
public function getInsertId(?string $sequence): ?int
|
public function getInsertId(?string $sequence): ?int
|
||||||
{
|
{
|
||||||
return $this->connection->insert_id;
|
return $this->connection->insert_id ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -290,37 +288,34 @@ class MySqliDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d'");
|
return $value->format("'Y-m-d'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d H:i:s.u'");
|
return $value->format("'Y-m-d H:i:s.u'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
if ($value->y || $value->m || $value->d) {
|
||||||
|
throw new Dibi\NotSupportedException('Only time interval is supported.');
|
||||||
|
}
|
||||||
|
return $value->format('%r%H:%I:%S.%f');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
public function escapeLike(string $value, int $pos): string
|
public function escapeLike(string $value, int $pos): string
|
||||||
{
|
{
|
||||||
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
|
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -334,7 +329,7 @@ class MySqliDriver implements Dibi\Driver
|
|||||||
|
|
||||||
} elseif ($limit !== null || $offset) {
|
} elseif ($limit !== null || $offset) {
|
||||||
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
|
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
|
||||||
$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : $limit)
|
$sql .= ' LIMIT ' . ($limit ?? '18446744073709551615')
|
||||||
. ($offset ? ' OFFSET ' . $offset : '');
|
. ($offset ? ' OFFSET ' . $offset : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,9 +37,7 @@ class OdbcDriver implements Dibi\Driver
|
|||||||
private $microseconds = true;
|
private $microseconds = true;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('odbc')) {
|
if (!extension_loaded('odbc')) {
|
||||||
@@ -226,37 +224,31 @@ class OdbcDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format('#m/d/Y#');
|
return $value->format('#m/d/Y#');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format($this->microseconds ? '#m/d/Y H:i:s.u#' : '#m/d/Y H:i:s#');
|
return $value->format($this->microseconds ? '#m/d/Y H:i:s.u#' : '#m/d/Y H:i:s#');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
throw new Dibi\NotImplementedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
public function escapeLike(string $value, int $pos): string
|
public function escapeLike(string $value, int $pos): string
|
||||||
{
|
{
|
||||||
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -42,9 +42,7 @@ class OracleDriver implements Dibi\Driver
|
|||||||
private $affectedRows;
|
private $affectedRows;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('oci8')) {
|
if (!extension_loaded('oci8')) {
|
||||||
@@ -52,10 +50,6 @@ class OracleDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
$foo = &$config['charset'];
|
$foo = &$config['charset'];
|
||||||
|
|
||||||
if (isset($config['formatDate']) || isset($config['formatDateTime'])) {
|
|
||||||
trigger_error('OracleDriver: options formatDate and formatDateTime are deprecated.', E_USER_DEPRECATED);
|
|
||||||
}
|
|
||||||
$this->nativeDate = $config['nativeDate'] ?? true;
|
$this->nativeDate = $config['nativeDate'] ?? true;
|
||||||
|
|
||||||
if (isset($config['resource'])) {
|
if (isset($config['resource'])) {
|
||||||
@@ -245,34 +239,28 @@ class OracleDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $this->nativeDate
|
return $this->nativeDate
|
||||||
? "to_date('" . $value->format('Y-m-d') . "', 'YYYY-mm-dd')"
|
? "to_date('" . $value->format('Y-m-d') . "', 'YYYY-mm-dd')"
|
||||||
: $value->format('U');
|
: $value->format('U');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $this->nativeDate
|
return $this->nativeDate
|
||||||
? "to_date('" . $value->format('Y-m-d G:i:s') . "', 'YYYY-mm-dd hh24:mi:ss')"
|
? "to_date('" . $value->format('Y-m-d G:i:s') . "', 'YYYY-mm-dd hh24:mi:ss')"
|
||||||
: $value->format('U');
|
: $value->format('U');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
throw new Dibi\NotImplementedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
@@ -280,7 +268,7 @@ class OracleDriver implements Dibi\Driver
|
|||||||
{
|
{
|
||||||
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
|
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
|
||||||
$value = str_replace("'", "''", $value);
|
$value = str_replace("'", "''", $value);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -96,6 +96,7 @@ class OracleResult implements Dibi\ResultDriver
|
|||||||
'name' => oci_field_name($this->resultSet, $i),
|
'name' => oci_field_name($this->resultSet, $i),
|
||||||
'table' => null,
|
'table' => null,
|
||||||
'fullname' => oci_field_name($this->resultSet, $i),
|
'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,
|
'nativetype' => $type === 'NUMBER' && oci_field_scale($this->resultSet, $i) === 0 ? 'INTEGER' : $type,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -42,9 +42,7 @@ class PdoDriver implements Dibi\Driver
|
|||||||
private $serverVersion = '';
|
private $serverVersion = '';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('pdo')) {
|
if (!extension_loaded('pdo')) {
|
||||||
@@ -289,26 +287,14 @@ class PdoDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format($this->driverName === 'odbc' ? '#m/d/Y#' : "'Y-m-d'");
|
return $value->format($this->driverName === 'odbc' ? '#m/d/Y#' : "'Y-m-d'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
switch ($this->driverName) {
|
switch ($this->driverName) {
|
||||||
case 'odbc':
|
case 'odbc':
|
||||||
return $value->format('#m/d/Y H:i:s.u#');
|
return $value->format('#m/d/Y H:i:s.u#');
|
||||||
@@ -322,6 +308,12 @@ class PdoDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
throw new Dibi\NotImplementedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
@@ -330,29 +322,29 @@ class PdoDriver implements Dibi\Driver
|
|||||||
switch ($this->driverName) {
|
switch ($this->driverName) {
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
|
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
|
|
||||||
case 'oci':
|
case 'oci':
|
||||||
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
|
$value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\\%_");
|
||||||
$value = str_replace("'", "''", $value);
|
$value = str_replace("'", "''", $value);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
|
|
||||||
case 'pgsql':
|
case 'pgsql':
|
||||||
$bs = substr($this->connection->quote('\\', PDO::PARAM_STR), 1, -1); // standard_conforming_strings = on/off
|
$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 = substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1);
|
||||||
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
|
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
|
|
||||||
case 'sqlite':
|
case 'sqlite':
|
||||||
$value = addcslashes(substr($this->connection->quote($value, PDO::PARAM_STR), 1, -1), '%_\\');
|
$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 'odbc':
|
||||||
case 'mssql':
|
case 'mssql':
|
||||||
case 'dblib':
|
case 'dblib':
|
||||||
case 'sqlsrv':
|
case 'sqlsrv':
|
||||||
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Dibi\NotImplementedException;
|
throw new Dibi\NotImplementedException;
|
||||||
@@ -373,7 +365,7 @@ class PdoDriver implements Dibi\Driver
|
|||||||
case 'mysql':
|
case 'mysql':
|
||||||
if ($limit !== null || $offset) {
|
if ($limit !== null || $offset) {
|
||||||
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
|
// see http://dev.mysql.com/doc/refman/5.0/en/select.html
|
||||||
$sql .= ' LIMIT ' . ($limit === null ? '18446744073709551615' : $limit)
|
$sql .= ' LIMIT ' . ($limit ?? '18446744073709551615')
|
||||||
. ($offset ? ' OFFSET ' . $offset : '');
|
. ($offset ? ' OFFSET ' . $offset : '');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -389,7 +381,7 @@ class PdoDriver implements Dibi\Driver
|
|||||||
|
|
||||||
case 'sqlite':
|
case 'sqlite':
|
||||||
if ($limit !== null || $offset) {
|
if ($limit !== null || $offset) {
|
||||||
$sql .= ' LIMIT ' . ($limit === null ? '-1' : $limit)
|
$sql .= ' LIMIT ' . ($limit ?? '-1')
|
||||||
. ($offset ? ' OFFSET ' . $offset : '');
|
. ($offset ? ' OFFSET ' . $offset : '');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -35,9 +35,7 @@ class PostgreDriver implements Dibi\Driver
|
|||||||
private $affectedRows;
|
private $affectedRows;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('pgsql')) {
|
if (!extension_loaded('pgsql')) {
|
||||||
@@ -71,7 +69,7 @@ class PostgreDriver implements Dibi\Driver
|
|||||||
if (empty($config['persistent'])) {
|
if (empty($config['persistent'])) {
|
||||||
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
|
$this->connection = pg_connect($string, PGSQL_CONNECT_FORCE_NEW);
|
||||||
} else {
|
} else {
|
||||||
$this->connection = pg_pconnect($string, PGSQL_CONNECT_FORCE_NEW);
|
$this->connection = pg_pconnect($string);
|
||||||
}
|
}
|
||||||
restore_error_handler();
|
restore_error_handler();
|
||||||
}
|
}
|
||||||
@@ -292,30 +290,24 @@ class PostgreDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d'");
|
return $value->format("'Y-m-d'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d H:i:s.u'");
|
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.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
@@ -324,7 +316,7 @@ class PostgreDriver implements Dibi\Driver
|
|||||||
$bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off
|
$bs = pg_escape_string($this->connection, '\\'); // standard_conforming_strings = on/off
|
||||||
$value = pg_escape_string($this->connection, $value);
|
$value = pg_escape_string($this->connection, $value);
|
||||||
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
|
$value = strtr($value, ['%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\']);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -37,9 +37,7 @@ class SqliteDriver implements Dibi\Driver
|
|||||||
private $fmtDateTime;
|
private $fmtDateTime;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('sqlite3')) {
|
if (!extension_loaded('sqlite3')) {
|
||||||
@@ -139,7 +137,7 @@ class SqliteDriver implements Dibi\Driver
|
|||||||
*/
|
*/
|
||||||
public function getInsertId(?string $sequence): ?int
|
public function getInsertId(?string $sequence): ?int
|
||||||
{
|
{
|
||||||
return $this->connection->lastInsertRowID();
|
return $this->connection->lastInsertRowID() ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -230,37 +228,31 @@ class SqliteDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format($this->fmtDate);
|
return $value->format($this->fmtDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format($this->fmtDateTime);
|
return $value->format($this->fmtDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function escapeDateInterval(\DateInterval $value): string
|
||||||
|
{
|
||||||
|
throw new Dibi\NotImplementedException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
public function escapeLike(string $value, int $pos): string
|
public function escapeLike(string $value, int $pos): string
|
||||||
{
|
{
|
||||||
$value = addcslashes($this->connection->escapeString($value), '%_\\');
|
$value = addcslashes($this->connection->escapeString($value), '%_\\');
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'") . " ESCAPE '\\'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -273,7 +265,7 @@ class SqliteDriver implements Dibi\Driver
|
|||||||
throw new Dibi\NotSupportedException('Negative offset or limit.');
|
throw new Dibi\NotSupportedException('Negative offset or limit.');
|
||||||
|
|
||||||
} elseif ($limit !== null || $offset) {
|
} elseif ($limit !== null || $offset) {
|
||||||
$sql .= ' LIMIT ' . ($limit === null ? '-1' : $limit)
|
$sql .= ' LIMIT ' . ($limit ?? '-1')
|
||||||
. ($offset ? ' OFFSET ' . $offset : '');
|
. ($offset ? ' OFFSET ' . $offset : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,7 @@ class SqliteResult implements Dibi\ResultDriver
|
|||||||
'name' => $this->resultSet->columnName($i),
|
'name' => $this->resultSet->columnName($i),
|
||||||
'table' => null,
|
'table' => null,
|
||||||
'fullname' => $this->resultSet->columnName($i),
|
'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;
|
return $columns;
|
||||||
|
@@ -39,9 +39,7 @@ class SqlsrvDriver implements Dibi\Driver
|
|||||||
private $version = '';
|
private $version = '';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @throws Dibi\NotSupportedException */
|
||||||
* @throws Dibi\NotSupportedException
|
|
||||||
*/
|
|
||||||
public function __construct(array $config)
|
public function __construct(array $config)
|
||||||
{
|
{
|
||||||
if (!extension_loaded('sqlsrv')) {
|
if (!extension_loaded('sqlsrv')) {
|
||||||
@@ -196,7 +194,7 @@ class SqlsrvDriver implements Dibi\Driver
|
|||||||
*/
|
*/
|
||||||
public function escapeText(string $value): string
|
public function escapeText(string $value): string
|
||||||
{
|
{
|
||||||
return "'" . str_replace("'", "''", $value) . "'";
|
return "N'" . str_replace("'", "''", $value) . "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -219,37 +217,31 @@ class SqlsrvDriver implements Dibi\Driver
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDate(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDate($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return $value->format("'Y-m-d'");
|
return $value->format("'Y-m-d'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
public function escapeDateTime(\DateTimeInterface $value): string
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
public function escapeDateTime($value): string
|
|
||||||
{
|
{
|
||||||
if (!$value instanceof \DateTimeInterface) {
|
|
||||||
$value = new Dibi\DateTime($value);
|
|
||||||
}
|
|
||||||
return 'CONVERT(DATETIME2(7), ' . $value->format("'Y-m-d H:i:s.u'") . ')';
|
return 'CONVERT(DATETIME2(7), ' . $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.
|
* Encodes string for use in a LIKE statement.
|
||||||
*/
|
*/
|
||||||
public function escapeLike(string $value, int $pos): string
|
public function escapeLike(string $value, int $pos): string
|
||||||
{
|
{
|
||||||
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
|
||||||
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
|
return ($pos & 1 ? "'%" : "'") . $value . ($pos & 2 ? "%'" : "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -100,7 +100,7 @@ class SqlsrvReflector implements Dibi\Reflector
|
|||||||
*/
|
*/
|
||||||
public function getIndexes(string $table): array
|
public function getIndexes(string $table): array
|
||||||
{
|
{
|
||||||
$keyUsagesRes = $this->driver->query(sprintf('EXEC [sys].[sp_helpindex] @objname = N%s', $this->driver->escapeText($table)));
|
$keyUsagesRes = $this->driver->query(sprintf('EXEC [sys].[sp_helpindex] @objname = %s', $this->driver->escapeText($table)));
|
||||||
$keyUsages = [];
|
$keyUsages = [];
|
||||||
while ($row = $keyUsagesRes->fetch(true)) {
|
while ($row = $keyUsagesRes->fetch(true)) {
|
||||||
$keyUsages[$row['index_name']] = explode(',', $row['index_keys']);
|
$keyUsages[$row['index_name']] = explode(',', $row['index_keys']);
|
||||||
|
@@ -61,7 +61,7 @@ class SqlsrvResult implements Dibi\ResultDriver
|
|||||||
*/
|
*/
|
||||||
public function fetch(bool $assoc): ?array
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -423,7 +423,7 @@ class Fluent implements IDataSource
|
|||||||
if ($clause === null) {
|
if ($clause === null) {
|
||||||
$data = $this->clauses;
|
$data = $this->clauses;
|
||||||
if ($this->command === 'SELECT' && ($data['LIMIT'] || $data['OFFSET'])) {
|
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']);
|
unset($data['LIMIT'], $data['OFFSET']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -201,9 +201,7 @@ class Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public static function getTypeCache(): HashMap
|
public static function getTypeCache(): HashMap
|
||||||
{
|
{
|
||||||
if (self::$types === null) {
|
if (self::$types === null) {
|
||||||
@@ -279,18 +277,14 @@ class Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public static function false2Null($val)
|
public static function false2Null($val)
|
||||||
{
|
{
|
||||||
return $val === false ? null : $val;
|
return $val === false ? null : $val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @internal */
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public static function intVal($value): int
|
public static function intVal($value): int
|
||||||
{
|
{
|
||||||
if (is_int($value)) {
|
if (is_int($value)) {
|
||||||
|
@@ -25,11 +25,15 @@ class FileLogger
|
|||||||
/** @var int */
|
/** @var int */
|
||||||
public $filter;
|
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->file = $file;
|
||||||
$this->filter = $filter ?: Dibi\Event::QUERY;
|
$this->filter = $filter ?: Dibi\Event::QUERY;
|
||||||
|
$this->errorsOnly = $errorsOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -38,39 +42,41 @@ class FileLogger
|
|||||||
*/
|
*/
|
||||||
public function logEvent(Dibi\Event $event): void
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$handle = fopen($this->file, 'a');
|
|
||||||
if (!$handle) {
|
|
||||||
return; // or throw exception?
|
|
||||||
}
|
|
||||||
flock($handle, LOCK_EX);
|
|
||||||
|
|
||||||
if ($event->result instanceof \Exception) {
|
if ($event->result instanceof \Exception) {
|
||||||
$message = $event->result->getMessage();
|
$message = $event->result->getMessage();
|
||||||
if ($code = $event->result->getCode()) {
|
if ($code = $event->result->getCode()) {
|
||||||
$message = "[$code] $message";
|
$message = "[$code] $message";
|
||||||
}
|
}
|
||||||
fwrite($handle,
|
$this->writeToFile(
|
||||||
|
$event,
|
||||||
"ERROR: $message"
|
"ERROR: $message"
|
||||||
. "\n-- SQL: " . $event->sql
|
. "\n-- SQL: " . $event->sql
|
||||||
. "\n-- driver: " . $event->connection->getConfig('driver') . '/' . $event->connection->getConfig('name')
|
|
||||||
. ";\n-- " . date('Y-m-d H:i:s')
|
|
||||||
. "\n\n"
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
fwrite($handle,
|
$this->writeToFile(
|
||||||
|
$event,
|
||||||
'OK: ' . $event->sql
|
'OK: ' . $event->sql
|
||||||
. ($event->count ? ";\n-- rows: " . $event->count : '')
|
. ($event->count ? ";\n-- rows: " . $event->count : '')
|
||||||
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
|
. "\n-- takes: " . sprintf('%0.3f ms', $event->time * 1000)
|
||||||
. "\n-- source: " . implode(':', $event->source)
|
. "\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"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -106,18 +106,14 @@ class Column
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return mixed */
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getDefault()
|
public function getDefault()
|
||||||
{
|
{
|
||||||
return $this->info['default'] ?? null;
|
return $this->info['default'] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return mixed */
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getVendorInfo(string $key)
|
public function getVendorInfo(string $key)
|
||||||
{
|
{
|
||||||
return $this->info['vendor'][$key] ?? null;
|
return $this->info['vendor'][$key] ?? null;
|
||||||
|
@@ -46,9 +46,7 @@ class Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return Table[] */
|
||||||
* @return Table[]
|
|
||||||
*/
|
|
||||||
public function getTables(): array
|
public function getTables(): array
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
@@ -56,9 +54,7 @@ class Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getTableNames(): array
|
public function getTableNames(): array
|
||||||
{
|
{
|
||||||
$this->init();
|
$this->init();
|
||||||
|
@@ -28,7 +28,7 @@ class Result
|
|||||||
/** @var Column[]|null */
|
/** @var Column[]|null */
|
||||||
private $columns;
|
private $columns;
|
||||||
|
|
||||||
/** @var string[]|null */
|
/** @var Column[]|null */
|
||||||
private $names;
|
private $names;
|
||||||
|
|
||||||
|
|
||||||
@@ -38,9 +38,7 @@ class Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return Column[] */
|
||||||
* @return Column[]
|
|
||||||
*/
|
|
||||||
public function getColumns(): array
|
public function getColumns(): array
|
||||||
{
|
{
|
||||||
$this->initColumns();
|
$this->initColumns();
|
||||||
@@ -48,9 +46,7 @@ class Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getColumnNames(bool $fullNames = false): array
|
public function getColumnNames(bool $fullNames = false): array
|
||||||
{
|
{
|
||||||
$this->initColumns();
|
$this->initColumns();
|
||||||
|
@@ -69,9 +69,7 @@ class Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return Column[] */
|
||||||
* @return Column[]
|
|
||||||
*/
|
|
||||||
public function getColumns(): array
|
public function getColumns(): array
|
||||||
{
|
{
|
||||||
$this->initColumns();
|
$this->initColumns();
|
||||||
@@ -79,9 +77,7 @@ class Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return string[] */
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function getColumnNames(): array
|
public function getColumnNames(): array
|
||||||
{
|
{
|
||||||
$this->initColumns();
|
$this->initColumns();
|
||||||
@@ -113,9 +109,7 @@ class Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return ForeignKey[] */
|
||||||
* @return ForeignKey[]
|
|
||||||
*/
|
|
||||||
public function getForeignKeys(): array
|
public function getForeignKeys(): array
|
||||||
{
|
{
|
||||||
$this->initForeignKeys();
|
$this->initForeignKeys();
|
||||||
@@ -123,9 +117,7 @@ class Table
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return Index[] */
|
||||||
* @return Index[]
|
|
||||||
*/
|
|
||||||
public function getIndexes(): array
|
public function getIndexes(): array
|
||||||
{
|
{
|
||||||
$this->initIndexes();
|
$this->initIndexes();
|
||||||
|
@@ -282,7 +282,7 @@ class Result implements IDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
} elseif ($as !== '|') { // associative-array node
|
} elseif ($as !== '|') { // associative-array node
|
||||||
$x = &$x[$row->$as];
|
$x = &$x[(string) $row->$as];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,9 +296,7 @@ class Result implements IDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @deprecated */
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
private function oldFetchAssoc(string $assoc)
|
private function oldFetchAssoc(string $assoc)
|
||||||
{
|
{
|
||||||
$this->seek(0);
|
$this->seek(0);
|
||||||
@@ -350,7 +348,7 @@ class Result implements IDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else { // associative-array node
|
} else { // associative-array node
|
||||||
$x = &$x[$row->$as];
|
$x = &$x[(string) $row->$as];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,6 +450,7 @@ class Result implements IDataSource
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$value = $row[$key];
|
$value = $row[$key];
|
||||||
|
|
||||||
if ($type === Type::TEXT) {
|
if ($type === Type::TEXT) {
|
||||||
$row[$key] = (string) $value;
|
$row[$key] = (string) $value;
|
||||||
|
|
||||||
@@ -496,7 +495,17 @@ class Result implements IDataSource
|
|||||||
$row[$key] = is_string($value) ? $this->getResultDriver()->unescapeBinary($value) : $value;
|
$row[$key] = is_string($value) ? $this->getResultDriver()->unescapeBinary($value) : $value;
|
||||||
|
|
||||||
} elseif ($type === Type::JSON) {
|
} elseif ($type === Type::JSON) {
|
||||||
$row[$key] = json_decode($value, true);
|
if ($this->formats[$type] === 'string') {
|
||||||
|
$row[$key] = $value;
|
||||||
|
} else {
|
||||||
|
$row[$key] = json_decode($value, $this->formats[$type] === 'array');
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($type === null) {
|
||||||
|
$row[$key] = $value;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException('Unexpected type ' . $type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,9 +574,7 @@ class Result implements IDataSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** @return Reflection\Column[] */
|
||||||
* @return Reflection\Column[]
|
|
||||||
*/
|
|
||||||
final public function getColumns(): array
|
final public function getColumns(): array
|
||||||
{
|
{
|
||||||
return $this->getInfo()->getColumns();
|
return $this->getInfo()->getColumns();
|
||||||
|
@@ -29,12 +29,6 @@ trait Strict
|
|||||||
*/
|
*/
|
||||||
public function __call(string $name, array $args)
|
public function __call(string $name, array $args)
|
||||||
{
|
{
|
||||||
$class = get_class($this);
|
|
||||||
if ($cb = self::extensionMethod($class . '::' . $name)) { // back compatiblity
|
|
||||||
trigger_error("Extension methods such as $class::$name() are deprecated", E_USER_DEPRECATED);
|
|
||||||
array_unshift($args, $this);
|
|
||||||
return $cb(...$args);
|
|
||||||
}
|
|
||||||
$class = method_exists($this, $name) ? 'parent' : get_class($this);
|
$class = method_exists($this, $name) ? 'parent' : get_class($this);
|
||||||
$items = (new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC);
|
$items = (new ReflectionClass($this))->getMethods(ReflectionMethod::IS_PUBLIC);
|
||||||
$hint = ($t = Helpers::getSuggestion($items, $name)) ? ", did you mean $t()?" : '.';
|
$hint = ($t = Helpers::getSuggestion($items, $name)) ? ", did you mean $t()?" : '.';
|
||||||
@@ -102,39 +96,4 @@ trait Strict
|
|||||||
$class = get_class($this);
|
$class = get_class($this);
|
||||||
throw new \LogicException("Attempt to unset undeclared property $class::$$name.");
|
throw new \LogicException("Attempt to unset undeclared property $class::$$name.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return mixed
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public static function extensionMethod(string $name, callable $callback = null)
|
|
||||||
{
|
|
||||||
if (strpos($name, '::') === false) {
|
|
||||||
$class = get_called_class();
|
|
||||||
} else {
|
|
||||||
[$class, $name] = explode('::', $name);
|
|
||||||
$class = (new ReflectionClass($class))->getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = &self::$extMethods[strtolower($name)];
|
|
||||||
if ($callback === null) { // getter
|
|
||||||
$cache = &$list[''][$class];
|
|
||||||
if (isset($cache)) {
|
|
||||||
return $cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ([$class] + class_parents($class) + class_implements($class) as $cl) {
|
|
||||||
if (isset($list[$cl])) {
|
|
||||||
return $cache = $list[$cl];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $cache = false;
|
|
||||||
|
|
||||||
} else { // setter
|
|
||||||
trigger_error("Extension methods such as $class::$name() are deprecated", E_USER_DEPRECATED);
|
|
||||||
$list[$class] = $callback;
|
|
||||||
$list[''] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -151,7 +151,7 @@ final class Translator
|
|||||||
$sql[] = '*/';
|
$sql[] = '*/';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql = implode(' ', $sql);
|
$sql = trim(implode(' ', $sql), ' ');
|
||||||
|
|
||||||
if ($this->errors) {
|
if ($this->errors) {
|
||||||
throw new Exception('SQL translate error: ' . trim(reset($this->errors), '*'), 0, $sql);
|
throw new Exception('SQL translate error: ' . trim(reset($this->errors), '*'), 0, $sql);
|
||||||
@@ -381,10 +381,11 @@ final class Translator
|
|||||||
case 'dt': // datetime
|
case 'dt': // datetime
|
||||||
if ($value === null) {
|
if ($value === null) {
|
||||||
return 'NULL';
|
return 'NULL';
|
||||||
} else {
|
} elseif (!$value instanceof \DateTimeInterface) {
|
||||||
return $modifier === 'd' ? $this->driver->escapeDate($value) : $this->driver->escapeDateTime($value);
|
$value = new DateTime($value);
|
||||||
}
|
}
|
||||||
// break omitted
|
return $modifier === 'd' ? $this->driver->escapeDate($value) : $this->driver->escapeDateTime($value);
|
||||||
|
|
||||||
case 'by':
|
case 'by':
|
||||||
case 'n': // composed identifier name
|
case 'n': // composed identifier name
|
||||||
return $this->identifiers->$value;
|
return $this->identifiers->$value;
|
||||||
@@ -414,12 +415,15 @@ final class Translator
|
|||||||
return (string) $value;
|
return (string) $value;
|
||||||
|
|
||||||
case 'like~': // LIKE string%
|
case 'like~': // LIKE string%
|
||||||
return $this->driver->escapeLike($value, 1);
|
return $this->driver->escapeLike($value, 2);
|
||||||
|
|
||||||
case '~like': // LIKE %string
|
case '~like': // LIKE %string
|
||||||
return $this->driver->escapeLike($value, -1);
|
return $this->driver->escapeLike($value, 1);
|
||||||
|
|
||||||
case '~like~': // LIKE %string%
|
case '~like~': // LIKE %string%
|
||||||
|
return $this->driver->escapeLike($value, 3);
|
||||||
|
|
||||||
|
case 'like': // LIKE string
|
||||||
return $this->driver->escapeLike($value, 0);
|
return $this->driver->escapeLike($value, 0);
|
||||||
|
|
||||||
case 'and':
|
case 'and':
|
||||||
@@ -455,6 +459,9 @@ final class Translator
|
|||||||
} elseif ($value instanceof \DateTimeInterface) {
|
} elseif ($value instanceof \DateTimeInterface) {
|
||||||
return $this->driver->escapeDateTime($value);
|
return $this->driver->escapeDateTime($value);
|
||||||
|
|
||||||
|
} elseif ($value instanceof \DateInterval) {
|
||||||
|
return $this->driver->escapeDateInterval($value);
|
||||||
|
|
||||||
} elseif ($value instanceof Literal) {
|
} elseif ($value instanceof Literal) {
|
||||||
return (string) $value;
|
return (string) $value;
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ class dibi
|
|||||||
|
|
||||||
/** version */
|
/** version */
|
||||||
public const
|
public const
|
||||||
VERSION = '4.0.2';
|
VERSION = '4.1.3';
|
||||||
|
|
||||||
/** sorting order */
|
/** sorting order */
|
||||||
public const
|
public const
|
||||||
@@ -145,26 +145,6 @@ class dibi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public static function affectedRows(): int
|
|
||||||
{
|
|
||||||
trigger_error(__METHOD__ . '() is deprecated, use getAffectedRows()', E_USER_DEPRECATED);
|
|
||||||
return self::getConnection()->getAffectedRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
public static function insertId(string $sequence = null): int
|
|
||||||
{
|
|
||||||
trigger_error(__METHOD__ . '() is deprecated, use getInsertId()', E_USER_DEPRECATED);
|
|
||||||
return self::getConnection()->getInsertId($sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/********************* misc tools ****************d*g**/
|
/********************* misc tools ****************d*g**/
|
||||||
|
|
||||||
|
|
||||||
|
@@ -87,15 +87,11 @@ interface Driver
|
|||||||
|
|
||||||
function escapeBool(bool $value): string;
|
function escapeBool(bool $value): string;
|
||||||
|
|
||||||
/**
|
function escapeDate(\DateTimeInterface $value): string;
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
|
||||||
function escapeDate($value): string;
|
|
||||||
|
|
||||||
/**
|
function escapeDateTime(\DateTimeInterface $value): string;
|
||||||
* @param \DateTimeInterface|string|int $value
|
|
||||||
*/
|
function escapeDateInterval(\DateInterval $value): string;
|
||||||
function escapeDateTime($value): string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes string for use in a LIKE statement.
|
* Encodes string for use in a LIKE statement.
|
||||||
|
@@ -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) {
|
test(function () use ($config) {
|
||||||
Assert::exception(function () use ($config) {
|
Assert::exception(function () use ($config) {
|
||||||
new Connection($config + ['onConnect' => '']);
|
new Connection($config + ['onConnect' => '']);
|
||||||
|
@@ -77,7 +77,7 @@ SELECT [product_id]
|
|||||||
FROM (SELECT * FROM products) t
|
FROM (SELECT * FROM products) t
|
||||||
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
||||||
ORDER BY [product_id] ASC
|
ORDER BY [product_id] ASC
|
||||||
) t"), dibi::$sql);
|
) t"), dibi::$sql);
|
||||||
Assert::same(1, $ds->toDataSource()->count());
|
Assert::same(1, $ds->toDataSource()->count());
|
||||||
|
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ SELECT [product_id]
|
|||||||
FROM (SELECT * FROM products) t
|
FROM (SELECT * FROM products) t
|
||||||
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
||||||
ORDER BY [product_id] ASC
|
ORDER BY [product_id] ASC
|
||||||
"),
|
"),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ SELECT [product_id]
|
|||||||
FROM (SELECT * FROM products) t
|
FROM (SELECT * FROM products) t
|
||||||
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
WHERE (title like '%a%') AND (product_id = 1) AND (product_id = 1)
|
||||||
ORDER BY [product_id] ASC
|
ORDER BY [product_id] ASC
|
||||||
) t"),
|
) t"),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -56,28 +56,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 TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
(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 TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t',
|
||||||
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 TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
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 TOP (3) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT TOP (1) * FROM ( SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
reformat('SELECT TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -85,16 +85,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 TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
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 TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT TOP (0) * FROM ( SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
reformat('SELECT TOP (0) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -103,12 +103,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 TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
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 TOP (1) * FROM (SELECT * FROM [customers] ORDER BY [customer_id]) t'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
|
@@ -22,28 +22,28 @@ $fluent = $conn->select('*')
|
|||||||
->orderBy('customer_id');
|
->orderBy('customer_id');
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
$fluent->fetch();
|
$fluent->fetch();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
$fluent->fetchSingle();
|
$fluent->fetchSingle();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
$fluent->fetchAll(2, 3);
|
$fluent->fetchAll(2, 3);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 3 OFFSET 2'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 3 OFFSET 2'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -51,16 +51,16 @@ Assert::same(
|
|||||||
$fluent->limit(0);
|
$fluent->limit(0);
|
||||||
$fluent->fetch();
|
$fluent->fetch();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
$fluent->fetchSingle();
|
$fluent->fetchSingle();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 0 OFFSET 3'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -68,16 +68,16 @@ Assert::same(
|
|||||||
$fluent->removeClause('limit');
|
$fluent->removeClause('limit');
|
||||||
$fluent->fetch();
|
$fluent->fetch();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
$fluent->fetchSingle();
|
$fluent->fetchSingle();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1 OFFSET 3'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 18446744073709551615 OFFSET 3'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 18446744073709551615 OFFSET 3'),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -85,12 +85,12 @@ Assert::same(
|
|||||||
$fluent->removeClause('offset');
|
$fluent->removeClause('offset');
|
||||||
$fluent->fetch();
|
$fluent->fetch();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
$fluent->fetchSingle();
|
$fluent->fetchSingle();
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat(' SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1'),
|
reformat('SELECT * FROM [customers] ORDER BY [customer_id] LIMIT 1'),
|
||||||
dibi::$sql
|
dibi::$sql
|
||||||
);
|
);
|
||||||
Assert::same(
|
Assert::same(
|
||||||
|
@@ -95,9 +95,9 @@ $fluent = $conn->select('*')
|
|||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat([
|
reformat([
|
||||||
'odbc' => 'SELECT TOP 1 * FROM ( SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123) t',
|
'odbc' => 'SELECT TOP 1 * FROM (SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123) t',
|
||||||
'sqlsrv' => ' SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY',
|
'sqlsrv' => 'SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123 OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY',
|
||||||
' SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123 LIMIT 1',
|
'SELECT * , (SELECT count(*) FROM [precteni] AS [P] WHERE P.id_clanku = C.id_clanku) FROM [clanky] AS [C] WHERE id_clanku=123 LIMIT 1',
|
||||||
]),
|
]),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
@@ -134,7 +134,10 @@ $fluent = $conn->select('*')
|
|||||||
->where(['x' => 'a', 'b', 'c']);
|
->where(['x' => 'a', 'b', 'c']);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT * FROM [me] AS [t] WHERE col > 10 AND ([x] = \'a\') AND (b) AND (c)'),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT * FROM [me] AS [t] WHERE col > 10 AND ([x] = N'a') AND (b) AND (c)",
|
||||||
|
"SELECT * FROM [me] AS [t] WHERE col > 10 AND ([x] = 'a') AND (b) AND (c)",
|
||||||
|
]),
|
||||||
(string) $fluent
|
(string) $fluent
|
||||||
);
|
);
|
||||||
|
|
||||||
|
25
tests/dibi/Translator.DateInterval.phpt
Normal file
25
tests/dibi/Translator.DateInterval.phpt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Tester\Assert;
|
||||||
|
|
||||||
|
require __DIR__ . '/bootstrap.php';
|
||||||
|
|
||||||
|
$conn = new Dibi\Connection($config);
|
||||||
|
$translator = new Dibi\Translator($conn);
|
||||||
|
|
||||||
|
switch ($config['system']) {
|
||||||
|
case 'mysql':
|
||||||
|
Assert::equal('10:20:30.0', $translator->formatValue(new DateInterval('PT10H20M30S'), null));
|
||||||
|
Assert::equal('-1:00:00.0', $translator->formatValue(DateInterval::createFromDateString('-1 hour'), null));
|
||||||
|
Assert::exception(function () use ($translator) {
|
||||||
|
$translator->formatValue(new DateInterval('P2Y4DT6H8M'), null);
|
||||||
|
}, Dibi\NotSupportedException::class, 'Only time interval is supported.');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Assert::exception(function () use ($translator) {
|
||||||
|
$translator->formatValue(new DateInterval('PT10H20M30S'), null);
|
||||||
|
}, Dibi\Exception::class);
|
||||||
|
}
|
@@ -60,13 +60,22 @@ WHERE [id] > 0
|
|||||||
|
|
||||||
// nested condition
|
// nested condition
|
||||||
Assert::match(
|
Assert::match(
|
||||||
reformat("
|
reformat([
|
||||||
|
'sqlsrv' => "
|
||||||
|
SELECT *
|
||||||
|
FROM [customers]
|
||||||
|
WHERE
|
||||||
|
[name] LIKE N'xxx'
|
||||||
|
/* AND ...=1 */
|
||||||
|
/* 1 LIMIT 10 */",
|
||||||
|
"
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM [customers]
|
FROM [customers]
|
||||||
WHERE
|
WHERE
|
||||||
[name] LIKE 'xxx'
|
[name] LIKE 'xxx'
|
||||||
/* AND ...=1 */
|
/* AND ...=1 */
|
||||||
/* 1 LIMIT 10 */"),
|
/* 1 LIMIT 10 */",
|
||||||
|
]),
|
||||||
|
|
||||||
$conn->translate('
|
$conn->translate('
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@@ -71,3 +71,9 @@ Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'baa', 'aa'));
|
|||||||
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'aab', 'aa'));
|
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'aab', 'aa'));
|
||||||
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like~', 'bba', '%a'));
|
Assert::falsey($conn->fetchSingle('SELECT ? LIKE %~like~', 'bba', '%a'));
|
||||||
Assert::truthy($conn->fetchSingle('SELECT ? LIKE %~like~', 'b%a', '%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'));
|
||||||
|
@@ -16,7 +16,10 @@ $conn = new Dibi\Connection($config + ['formatDateTime' => "'Y-m-d H:i:s.u'", 'f
|
|||||||
|
|
||||||
// Dibi detects INSERT or REPLACE command & booleans
|
// Dibi detects INSERT or REPLACE command & booleans
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat("REPLACE INTO [products] ([title], [price]) VALUES ('Drticka', 318)"),
|
reformat([
|
||||||
|
'sqlsrv' => "REPLACE INTO [products] ([title], [price]) VALUES (N'Drticka', 318)",
|
||||||
|
"REPLACE INTO [products] ([title], [price]) VALUES ('Drticka', 318)",
|
||||||
|
]),
|
||||||
$conn->translate('REPLACE INTO [products]', [
|
$conn->translate('REPLACE INTO [products]', [
|
||||||
'title' => 'Drticka',
|
'title' => 'Drticka',
|
||||||
'price' => 318,
|
'price' => 318,
|
||||||
@@ -31,7 +34,10 @@ $array = [
|
|||||||
'brand' => null,
|
'brand' => null,
|
||||||
];
|
];
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('INSERT INTO [products] ([title], [price], [brand]) VALUES (\'Super Product\', 12, NULL) , (\'Super Product\', 12, NULL) , (\'Super Product\', 12, NULL)'),
|
reformat([
|
||||||
|
'sqlsrv' => "INSERT INTO [products] ([title], [price], [brand]) VALUES (N'Super Product', 12, NULL) , (N'Super Product', 12, NULL) , (N'Super Product', 12, NULL)",
|
||||||
|
"INSERT INTO [products] ([title], [price], [brand]) VALUES ('Super Product', 12, NULL) , ('Super Product', 12, NULL) , ('Super Product', 12, NULL)",
|
||||||
|
]),
|
||||||
$conn->translate('INSERT INTO [products]', $array, $array, $array)
|
$conn->translate('INSERT INTO [products]', $array, $array, $array)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -43,14 +49,20 @@ $array = [
|
|||||||
['pole' => 'hodnota3', 'bit' => 1],
|
['pole' => 'hodnota3', 'bit' => 1],
|
||||||
];
|
];
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('INSERT INTO [products] ([pole], [bit]) VALUES (\'hodnota1\', 1) , (\'hodnota2\', 1) , (\'hodnota3\', 1)'),
|
reformat([
|
||||||
|
'sqlsrv' => "INSERT INTO [products] ([pole], [bit]) VALUES (N'hodnota1', 1) , (N'hodnota2', 1) , (N'hodnota3', 1)",
|
||||||
|
"INSERT INTO [products] ([pole], [bit]) VALUES ('hodnota1', 1) , ('hodnota2', 1) , ('hodnota3', 1)",
|
||||||
|
]),
|
||||||
$conn->translate('INSERT INTO [products] %ex', $array)
|
$conn->translate('INSERT INTO [products] %ex', $array)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// Dibi detects UPDATE command
|
// Dibi detects UPDATE command
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat("UPDATE [colors] SET [color]='blue', [order]=12 WHERE [id]=123"),
|
reformat([
|
||||||
|
'sqlsrv' => "UPDATE [colors] SET [color]=N'blue', [order]=12 WHERE [id]=123",
|
||||||
|
"UPDATE [colors] SET [color]='blue', [order]=12 WHERE [id]=123",
|
||||||
|
]),
|
||||||
$conn->translate('UPDATE [colors] SET', [
|
$conn->translate('UPDATE [colors] SET', [
|
||||||
'color' => 'blue',
|
'color' => 'blue',
|
||||||
'order' => 12,
|
'order' => 12,
|
||||||
@@ -85,17 +97,26 @@ $e = Assert::exception(function () use ($conn) {
|
|||||||
Assert::same('SELECT **Invalid combination of type stdClass and modifier %s** , **Unknown or unexpected modifier %m**', $e->getSql());
|
Assert::same('SELECT **Invalid combination of type stdClass and modifier %s** , **Unknown or unexpected modifier %m**', $e->getSql());
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT * FROM [table] WHERE id=10 AND name=\'ahoj\''),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT * FROM [table] WHERE id=10 AND name=N'ahoj'",
|
||||||
|
"SELECT * FROM [table] WHERE id=10 AND name='ahoj'",
|
||||||
|
]),
|
||||||
$conn->translate('SELECT * FROM [table] WHERE id=%i AND name=%s', 10, 'ahoj')
|
$conn->translate('SELECT * FROM [table] WHERE id=%i AND name=%s', 10, 'ahoj')
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('TEST ([cond] > 2) OR ([cond2] = \'3\') OR (cond3 < RAND())'),
|
reformat([
|
||||||
|
'sqlsrv' => "TEST ([cond] > 2) OR ([cond2] = N'3') OR (cond3 < RAND())",
|
||||||
|
"TEST ([cond] > 2) OR ([cond2] = '3') OR (cond3 < RAND())",
|
||||||
|
]),
|
||||||
$conn->translate('TEST %or', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'])
|
$conn->translate('TEST %or', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'])
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('TEST ([cond] > 2) AND ([cond2] = \'3\') AND (cond3 < RAND())'),
|
reformat([
|
||||||
|
'sqlsrv' => "TEST ([cond] > 2) AND ([cond2] = N'3') AND (cond3 < RAND())",
|
||||||
|
"TEST ([cond] > 2) AND ([cond2] = '3') AND (cond3 < RAND())",
|
||||||
|
]),
|
||||||
$conn->translate('TEST %and', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'])
|
$conn->translate('TEST %and', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'])
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -114,7 +135,10 @@ $where['age'] = null;
|
|||||||
$where['email'] = 'ahoj';
|
$where['email'] = 'ahoj';
|
||||||
$where['id%l'] = [10, 20, 30];
|
$where['id%l'] = [10, 20, 30];
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT * FROM [table] WHERE ([age] IS NULL) AND ([email] = \'ahoj\') AND ([id] IN (10, 20, 30))'),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT * FROM [table] WHERE ([age] IS NULL) AND ([email] = N'ahoj') AND ([id] IN (10, 20, 30))",
|
||||||
|
"SELECT * FROM [table] WHERE ([age] IS NULL) AND ([email] = 'ahoj') AND ([id] IN (10, 20, 30))",
|
||||||
|
]),
|
||||||
$conn->translate('SELECT * FROM [table] WHERE %and', $where)
|
$conn->translate('SELECT * FROM [table] WHERE %and', $where)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -144,9 +168,9 @@ Assert::same(
|
|||||||
// with limit = 2
|
// with limit = 2
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat([
|
reformat([
|
||||||
'odbc' => 'SELECT TOP 2 * FROM (SELECT * FROM [products] ) t',
|
'odbc' => 'SELECT TOP 2 * FROM (SELECT * FROM [products]) t',
|
||||||
'sqlsrv' => 'SELECT * FROM [products] OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY',
|
'sqlsrv' => 'SELECT * FROM [products] OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY',
|
||||||
'SELECT * FROM [products] LIMIT 2',
|
'SELECT * FROM [products] LIMIT 2',
|
||||||
]),
|
]),
|
||||||
$conn->translate('SELECT * FROM [products] %lmt', 2)
|
$conn->translate('SELECT * FROM [products] %lmt', 2)
|
||||||
);
|
);
|
||||||
@@ -160,7 +184,7 @@ if ($config['system'] === 'odbc') {
|
|||||||
Assert::same(
|
Assert::same(
|
||||||
reformat([
|
reformat([
|
||||||
'sqlsrv' => 'SELECT * FROM [products] OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY',
|
'sqlsrv' => 'SELECT * FROM [products] OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY',
|
||||||
'SELECT * FROM [products] LIMIT 2 OFFSET 1',
|
'SELECT * FROM [products] LIMIT 2 OFFSET 1',
|
||||||
]),
|
]),
|
||||||
$conn->translate('SELECT * FROM [products] %lmt %ofs', 2, 1)
|
$conn->translate('SELECT * FROM [products] %lmt %ofs', 2, 1)
|
||||||
);
|
);
|
||||||
@@ -168,10 +192,10 @@ if ($config['system'] === 'odbc') {
|
|||||||
// with offset = 50
|
// with offset = 50
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat([
|
reformat([
|
||||||
'mysql' => 'SELECT * FROM `products` LIMIT 18446744073709551615 OFFSET 50',
|
'mysql' => 'SELECT * FROM `products` LIMIT 18446744073709551615 OFFSET 50',
|
||||||
'postgre' => 'SELECT * FROM "products" OFFSET 50',
|
'postgre' => 'SELECT * FROM "products" OFFSET 50',
|
||||||
'sqlsrv' => 'SELECT * FROM [products] OFFSET 50 ROWS',
|
'sqlsrv' => 'SELECT * FROM [products] OFFSET 50 ROWS',
|
||||||
'SELECT * FROM [products] LIMIT -1 OFFSET 50',
|
'SELECT * FROM [products] LIMIT -1 OFFSET 50',
|
||||||
]),
|
]),
|
||||||
$conn->translate('SELECT * FROM [products] %ofs', 50)
|
$conn->translate('SELECT * FROM [products] %ofs', 50)
|
||||||
);
|
);
|
||||||
@@ -259,7 +283,13 @@ INTO OUTFILE '/tmp/result\'.txt'
|
|||||||
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"'
|
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\\\"'
|
||||||
LINES TERMINATED BY '\\\\n'
|
LINES TERMINATED BY '\\\\n'
|
||||||
",
|
",
|
||||||
"SELECT DISTINCT HIGH_PRIORITY SQL_BUFFER_RESULT
|
'sqlsrv' => "SELECT DISTINCT HIGH_PRIORITY SQL_BUFFER_RESULT
|
||||||
|
CONCAT(last_name, N', ', first_name) AS full_name
|
||||||
|
GROUP BY [user]
|
||||||
|
HAVING MAX(salary) > %i 123
|
||||||
|
INTO OUTFILE N'/tmp/result''.txt'
|
||||||
|
FIELDS TERMINATED BY N',' OPTIONALLY ENCLOSED BY N'\"'
|
||||||
|
LINES TERMINATED BY N'\\n'", "SELECT DISTINCT HIGH_PRIORITY SQL_BUFFER_RESULT
|
||||||
CONCAT(last_name, ', ', first_name) AS full_name
|
CONCAT(last_name, ', ', first_name) AS full_name
|
||||||
GROUP BY [user]
|
GROUP BY [user]
|
||||||
HAVING MAX(salary) > %i 123
|
HAVING MAX(salary) > %i 123
|
||||||
@@ -321,6 +351,27 @@ WHERE (`test`.`a` LIKE '1995-03-01'
|
|||||||
OR `false`= 0
|
OR `false`= 0
|
||||||
OR `str_null`=NULL
|
OR `str_null`=NULL
|
||||||
OR `str_not_null`='hello'
|
OR `str_not_null`='hello'
|
||||||
|
LIMIT 10",
|
||||||
|
'sqlsrv' => "SELECT *
|
||||||
|
FROM [db].[table]
|
||||||
|
WHERE ([test].[a] LIKE '1995-03-01'
|
||||||
|
OR [b1] IN ( 1, 2, 3 )
|
||||||
|
OR [b2] IN (N'1', N'2', N'3' )
|
||||||
|
OR [b3] IN ( )
|
||||||
|
OR [b4] IN ( N'one', N'two', N'three' )
|
||||||
|
OR [b5] IN ([col1] AS [one], [col2] AS [two], [col3] AS [thr.ee] )
|
||||||
|
OR [b6] IN (N'one', N'two', N'thr.ee')
|
||||||
|
OR [b7] IN (NULL)
|
||||||
|
OR [b8] IN (RAND() [col1] > [col2] )
|
||||||
|
OR [b9] IN (RAND(), [col1] > [col2] )
|
||||||
|
OR [b10] IN ( )
|
||||||
|
AND [c] = N'embedded '' string'
|
||||||
|
OR [d]=10
|
||||||
|
OR [e]=NULL
|
||||||
|
OR [true]= 1
|
||||||
|
OR [false]= 0
|
||||||
|
OR [str_null]=NULL
|
||||||
|
OR [str_not_null]=N'hello'
|
||||||
LIMIT 10",
|
LIMIT 10",
|
||||||
'postgre' => 'SELECT *
|
'postgre' => 'SELECT *
|
||||||
FROM "db"."table"
|
FROM "db"."table"
|
||||||
@@ -412,7 +463,10 @@ LIMIT 10')
|
|||||||
|
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('TEST [cond] > 2 [cond2] = \'3\' cond3 < RAND() 123'),
|
reformat([
|
||||||
|
'sqlsrv' => "TEST [cond] > 2 [cond2] = N'3' cond3 < RAND() 123",
|
||||||
|
"TEST [cond] > 2 [cond2] = '3' cond3 < RAND() 123",
|
||||||
|
]),
|
||||||
$conn->translate('TEST %ex', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'], 123)
|
$conn->translate('TEST %ex', ['[cond] > 2', '[cond2] = "3"', 'cond3 < RAND()'], 123)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -430,16 +484,19 @@ Assert::same(
|
|||||||
|
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('TEST ([cond1] 3) OR ([cond2] RAND()) OR ([cond3] LIKE \'string\')'),
|
reformat([
|
||||||
|
'sqlsrv' => "TEST ([cond1] 3) OR ([cond2] RAND()) OR ([cond3] LIKE N'string')",
|
||||||
|
"TEST ([cond1] 3) OR ([cond2] RAND()) OR ([cond3] LIKE 'string')",
|
||||||
|
]),
|
||||||
$conn->translate('TEST %or', ['cond1%ex' => 3, 'cond2%ex' => 'RAND()', 'cond3%ex' => ['LIKE %s', 'string']])
|
$conn->translate('TEST %or', ['cond1%ex' => 3, 'cond2%ex' => 'RAND()', 'cond3%ex' => ['LIKE %s', 'string']])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat([
|
reformat([
|
||||||
'odbc' => 'SELECT TOP 10 * FROM (SELECT * FROM [test] WHERE [id] LIKE \'%d%t\' ) t',
|
'odbc' => 'SELECT TOP 10 * FROM (SELECT * FROM [test] WHERE [id] LIKE \'%d%t\') t',
|
||||||
'sqlsrv' => 'SELECT * FROM [test] WHERE [id] LIKE \'%d%t\' OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',
|
'sqlsrv' => 'SELECT * FROM [test] WHERE [id] LIKE N\'%d%t\' OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY',
|
||||||
'SELECT * FROM [test] WHERE [id] LIKE \'%d%t\' LIMIT 10',
|
'SELECT * FROM [test] WHERE [id] LIKE \'%d%t\' LIMIT 10',
|
||||||
]),
|
]),
|
||||||
$conn->translate("SELECT * FROM [test] WHERE %n LIKE '%d%t' %lmt", 'id', 10)
|
$conn->translate("SELECT * FROM [test] WHERE %n LIKE '%d%t' %lmt", 'id', 10)
|
||||||
);
|
);
|
||||||
@@ -455,23 +512,32 @@ Assert::same(
|
|||||||
|
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT FROM ... '),
|
reformat('SELECT FROM ...'),
|
||||||
$conn->translate('SELECT FROM ... %lmt', null)
|
$conn->translate('SELECT FROM ... %lmt', null)
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT \'%i\''),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT N'%i'",
|
||||||
|
"SELECT '%i'",
|
||||||
|
]),
|
||||||
$conn->translate("SELECT '%i'")
|
$conn->translate("SELECT '%i'")
|
||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT \'%i\''),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT N'%i'",
|
||||||
|
"SELECT '%i'",
|
||||||
|
]),
|
||||||
$conn->translate('SELECT "%i"')
|
$conn->translate('SELECT "%i"')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('INSERT INTO [products] ([product_id], [title]) VALUES (1, SHA1(\'Test product\')) , (1, SHA1(\'Test product\'))'),
|
reformat([
|
||||||
|
'sqlsrv' => "INSERT INTO [products] ([product_id], [title]) VALUES (1, SHA1(N'Test product')) , (1, SHA1(N'Test product'))",
|
||||||
|
"INSERT INTO [products] ([product_id], [title]) VALUES (1, SHA1('Test product')) , (1, SHA1('Test product'))",
|
||||||
|
]),
|
||||||
$conn->translate('INSERT INTO [products]', [
|
$conn->translate('INSERT INTO [products]', [
|
||||||
'product_id' => 1,
|
'product_id' => 1,
|
||||||
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
||||||
@@ -482,7 +548,10 @@ Assert::same(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('UPDATE [products] [product_id]=1, [title]=SHA1(\'Test product\')'),
|
reformat([
|
||||||
|
'sqlsrv' => "UPDATE [products] [product_id]=1, [title]=SHA1(N'Test product')",
|
||||||
|
"UPDATE [products] [product_id]=1, [title]=SHA1('Test product')",
|
||||||
|
]),
|
||||||
$conn->translate('UPDATE [products]', [
|
$conn->translate('UPDATE [products]', [
|
||||||
'product_id' => 1,
|
'product_id' => 1,
|
||||||
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
||||||
@@ -490,7 +559,10 @@ Assert::same(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('UPDATE [products] [product_id]=1, [title]=SHA1(\'Test product\')'),
|
reformat([
|
||||||
|
'sqlsrv' => "UPDATE [products] [product_id]=1, [title]=SHA1(N'Test product')",
|
||||||
|
"UPDATE [products] [product_id]=1, [title]=SHA1('Test product')",
|
||||||
|
]),
|
||||||
$conn->translate('UPDATE [products]', [
|
$conn->translate('UPDATE [products]', [
|
||||||
'product_id' => 1,
|
'product_id' => 1,
|
||||||
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
||||||
@@ -498,7 +570,10 @@ Assert::same(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('SELECT * FROM [products] WHERE [product_id]=1, [title]=SHA1(\'Test product\')'),
|
reformat([
|
||||||
|
'sqlsrv' => "SELECT * FROM [products] WHERE [product_id]=1, [title]=SHA1(N'Test product')",
|
||||||
|
"SELECT * FROM [products] WHERE [product_id]=1, [title]=SHA1('Test product')",
|
||||||
|
]),
|
||||||
$conn->translate('SELECT * FROM [products] WHERE', [
|
$conn->translate('SELECT * FROM [products] WHERE', [
|
||||||
'product_id' => 1,
|
'product_id' => 1,
|
||||||
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
'title' => new Dibi\Expression('SHA1(%s)', 'Test product'),
|
||||||
@@ -535,7 +610,10 @@ $array6 = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat('INSERT INTO test ([id], [text], [num]) VALUES (1, \'ahoj\', 1), (2, \'jak\', -1), (3, \'se\', 10), (4, SUM(5), 1)'),
|
reformat([
|
||||||
|
'sqlsrv' => "INSERT INTO test ([id], [text], [num]) VALUES (1, N'ahoj', 1), (2, N'jak', -1), (3, N'se', 10), (4, SUM(5), 1)",
|
||||||
|
"INSERT INTO test ([id], [text], [num]) VALUES (1, 'ahoj', 1), (2, 'jak', -1), (3, 'se', 10), (4, SUM(5), 1)",
|
||||||
|
]),
|
||||||
$conn->translate('INSERT INTO test %m', $array6)
|
$conn->translate('INSERT INTO test %m', $array6)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -589,7 +667,10 @@ Assert::same(
|
|||||||
setlocale(LC_ALL, 'czech');
|
setlocale(LC_ALL, 'czech');
|
||||||
|
|
||||||
Assert::same(
|
Assert::same(
|
||||||
reformat("UPDATE [colors] SET [color]='blue', [price]=-12.4, [spec]=-9E-005, [spec2]=1000, [spec3]=10000, [spec4]=10000 WHERE [price]=123.5"),
|
reformat([
|
||||||
|
'sqlsrv' => "UPDATE [colors] SET [color]=N'blue', [price]=-12.4, [spec]=-9E-005, [spec2]=1000, [spec3]=10000, [spec4]=10000 WHERE [price]=123.5",
|
||||||
|
"UPDATE [colors] SET [color]='blue', [price]=-12.4, [spec]=-9E-005, [spec2]=1000, [spec3]=10000, [spec4]=10000 WHERE [price]=123.5",
|
||||||
|
]),
|
||||||
|
|
||||||
$conn->translate('UPDATE [colors] SET', [
|
$conn->translate('UPDATE [colors] SET', [
|
||||||
'color' => 'blue',
|
'color' => 'blue',
|
||||||
|
4
tests/phpstan.neon
Normal file
4
tests/phpstan.neon
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
parameters:
|
||||||
|
ignoreErrors:
|
||||||
|
# The namespace is referenced, not the class.
|
||||||
|
- '#Class dibi referenced with incorrect case: Dibi#'
|
Reference in New Issue
Block a user