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

Compare commits

...

49 Commits

Author SHA1 Message Date
David Grudl
22e6ea4e40 Released version 3.0.7 2017-01-04 15:18:17 +01:00
David Grudl
f0d2c3f414 travis: removed PHP 7.1 from allowed failures 2017-01-04 15:18:17 +01:00
David Grudl
873ed3115d Connection::translateArgs() is protected [Closes #237] 2017-01-04 15:18:17 +01:00
Martin Dzíbela
73289d0569 PostgreSQL: add support for more than one schema in search_path (#239) 2017-01-04 15:18:17 +01:00
David Grudl
7b899ddda5 updated contributing.md, added GitHub templates 2017-01-04 15:18:17 +01:00
Ondřej Mirtes
8860268791 typos (#243) 2016-12-03 19:29:29 +01:00
Honza Machala
551b576271 Typos (#242) 2016-11-14 13:47:45 +01:00
David Grudl
74d0a78ec2 Result, Row: added support for datetime like 'Jun 17 2015 12:00:00:000AM' [Closes #180] 2016-09-02 17:36:37 +02:00
Aleš Culek
be7c3f095d Implemented OracleDriver::getColumns() (#233) 2016-08-09 22:37:45 +02:00
Radovan Kepák
3a6dc07da8 FirebirdDriver: Fixed DriverException throw (#231)
Fixed fetch Dibi\DriverException throw and more PHP warnings silenced
2016-08-09 22:36:44 +02:00
David Grudl
9b070bb737 Released version 3.0.6 2016-07-31 16:50:07 +02:00
David Grudl
917971992f Bridges\Tracy\Panel: silenced PHP warning
https://forum.nette.org/cs/26790-error-dibi-bridges-tracy-panel-oracle
2016-07-27 14:01:46 +02:00
Radovan Kepák
bc564555f8 FirebirdDriver: silenced PHP warning
If fetch have error, PHP show Warning, this is error by my opinion as Dibi Throw Exception with information, so the Warning is useless, and even more, if we catch exception, we still have warning.
2016-07-27 13:55:15 +02:00
David Grudl
3e20a6b8fc Dibi\DateTime::__wakeup() doesn't call parent after 8e8e6dfd [Closes #228] 2016-07-27 13:28:23 +02:00
David Grudl
c019e7cac2 tests: fixed compatibility with PHP 7.1 2016-07-21 14:38:56 +02:00
David Grudl
2294c195f4 Released version 3.0.5 2016-07-20 16:15:13 +02:00
David Grudl
25246529f7 Translator, Fluent: preserve dot in name after AS [Closes #224] 2016-07-20 16:13:33 +02:00
David Grudl
d405ec369b Translator: added %N 2016-07-20 16:13:32 +02:00
David Grudl
b7974fe192 travis: added PHP 7.1 2016-07-20 15:54:58 +02:00
David Grudl
80f1898e1b tests: removed deprecated 'storage_engine' 2016-07-20 15:50:33 +02:00
Roman Pavlík
8e8e6dfdca Dibi\DateTime: provides BC for serialized older versions [Closes #226] (#227) 2016-07-20 15:50:33 +02:00
Milan Pála
6510fcce25 Disconnect on not connected driver not fail (#222)
Sometimes database go away and Connection::isConnected() is returning TRUE. Prevent this should be posibble to disconnect on closed connection without error.
2016-07-20 15:50:32 +02:00
aldria
b7d84b90ef Correct limit and offset for Firebird Driver (#221)
SELECT [FIRST (<int-expr>)] [SKIP (<int-expr>)] <columns> FROM ...
2016-05-27 03:48:06 +02:00
David Grudl
2571e54f3c composer.json: replaces all dg/dibi versions 2016-05-04 20:13:50 +02:00
Aleš Culek
15e6d9f738 Implemented OracleDriver::getAffectedRows() 2016-05-03 08:55:22 +02:00
David Grudl
ddfd4a0f1a tests/travis: reports code coverage to Coveralls 2016-04-21 11:29:10 +02:00
David Grudl
4e838fc2b5 Released version 3.0.4 2016-04-06 19:09:24 +02:00
David Grudl
37487816db removed Strict from exceptions [Closes #216] 2016-04-06 18:52:42 +02:00
David Grudl
0c099bb2bc tests: a different .ini for PHP 5 and PHP 7 2016-03-20 19:23:57 +01:00
David Grudl
1786c861b9 Merge pull request #213 from castamir/php7sqlsrv
SqlsrvDriver: php7 compatibility
2016-03-20 16:34:36 +01:00
Mira Paulik
bc0578928f SqlsrvDriver: php7 compatibility 2016-03-20 13:50:10 +01:00
David Grudl
12a07ff6ad Merge pull request #212 from soukiii/master
Fluent: missing annotation
2016-03-18 17:16:23 +01:00
Petr Soukup
b50f59c64c Fluent: missing annotation 2016-03-18 15:40:16 +01:00
David Grudl
fdebf349f5 appveyor: test under PHP 7 2016-03-18 15:07:45 +01:00
David Grudl
954c2f25d0 Merge pull request #209 from castamir/sqlsrv_insert
SqlsrvDriver::getInsertId() last inserted id is from last statement instead of last inserted row
2016-02-29 23:37:17 +01:00
Mira Paulik
43dccb1ba2 SqlsrvDriver::getInsertId() last inserted id is from last statement instead of last inserted row regardless of the table that produced the value 2016-02-29 16:10:59 +01:00
David Grudl
352a683ec1 Released version 3.0.3 2016-02-21 02:07:19 +01:00
David Grudl
f4638796fb Helpers::detectType() detects VAR_STRING as Type::TEXT 2016-02-20 21:08:01 +01:00
David Grudl
4659f4550e DibiExtension22: added options 'explain' & 'filter' [Closes #203] 2016-02-10 00:08:27 +01:00
David Grudl
c3548465fb Merge pull request #204 from castamir/sqlsrv
SqlsrvDriver: fixed: sql server does not respond on non-string password
2016-02-09 23:19:53 +01:00
David Grudl
dda0bdbd67 Merge pull request #208 from ondrej-tuhacek/master
FirebirdDriver::delimite - Quotation marks for escaping identifiers
2016-02-04 16:08:25 +01:00
Ondřej Tuháček
7142be254b FirebirdDriver::delimite - Quotation marks for escaping identifiers 2016-02-04 13:29:06 +01:00
David Grudl
8948cc293c Released version 3.0.2 2016-01-29 15:46:23 +01:00
David Grudl
193252dc5f PdoDriver::applyLimit() is the same as SqlsrvDriver 2016-01-28 20:13:49 +01:00
Mira Paulik
6b2a46bcb8 appveyor: testing with SQL Server 2012 & 2014 2016-01-28 19:55:55 +01:00
Mira Paulik
2c01d993d0 SqlsrvReflector::getTables(): gets list of all tables from dbo schema only 2016-01-28 19:54:46 +01:00
Mira Paulik
e415157206 SqlsrvDriver::applyLimit(): fixed limit and offset behaviour for odbc 11+
SqlsrvReflector: changed constrains metadata loading from INFORMATION_SCHEMA to sys schema to get complete list of all constraints, not PK only
2016-01-28 19:48:49 +01:00
David Grudl
8a7dbcba86 Revert "removed MsSqlDriver (is not available with PHP 5.3 or later; replaced with SqlsrvDriver)"
This reverts commit ac1ab26e7a.
2016-01-24 22:52:18 +01:00
Mira Paulik
3b00115ee5 SqlsrvDriver: fixed: sql server does not respond on non-string credentials 2016-01-22 17:14:12 +01:00
50 changed files with 1031 additions and 142 deletions

1
.gitattributes vendored
View File

@@ -1,4 +1,5 @@
.gitattributes export-ignore
.gitignore export-ignore
.github export-ignore
.travis.yml export-ignore
tests/ export-ignore

16
.github/issue_template.md vendored Normal file
View File

@@ -0,0 +1,16 @@
- bug report? yes/no
- feature request? yes/no
- version: ?.?.? <!-- exact release version, for bug reports -->
### Description
...
### Steps To Reproduce
... If possible a minimal demo of the problem ...
<!--
REMEMBER, AN ISSUE IS NOT THE PLACE TO ASK QUESTIONS. We will be happy to help you on Gitter https://gitter.im/nette/nette
A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report.
Feature requests are welcome. Explain your intentions. It's up to you to make a strong case to convince the project's developers of the merits of this feature.
-->

11
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,11 @@
- bug fix? yes/no <!-- #issue numbers, if any -->
- new feature? yes/no
- BC break? yes/no
<!--
Describe your changes here to communicate to the maintainers why we should accept this pull request.
Please add new tests to show the fix or feature works.
Thanks for contributing!
-->

View File

@@ -4,6 +4,7 @@ php:
- 5.5
- 5.6
- 7.0
- 7.1
- hhvm
matrix:
@@ -11,7 +12,7 @@ matrix:
- php: hhvm
script:
- vendor/bin/tester tests -s -p php -c tests/php-unix.ini
- vendor/bin/tester tests -s -p php -c tests/php-unix.ini $COVERAGE
- php temp/code-checker/src/code-checker.php --short-arrays
after_failure:
@@ -22,6 +23,7 @@ before_script:
# Install Nette Tester & Code Checker
- travis_retry composer install --no-interaction
- travis_retry composer create-project nette/code-checker temp/code-checker ~2.5 --no-interaction
- if [ $TRAVIS_PHP_VERSION == "7.0" ]; then COVERAGE="-p phpdbg --coverage ./coverage.xml --coverage-src ./src"; fi
# Create databases.ini
- cp ./tests/databases.travis.ini ./tests/databases.ini
@@ -29,6 +31,14 @@ before_script:
# Create Postgre database
- psql -c 'CREATE DATABASE dibi_test' -U postgres
after_script:
# Report Code Coverage
- >
if [ "$COVERAGE" != "" ]; then
wget https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar
&& php coveralls.phar --verbose --config tests/.coveralls.yml
|| true; fi
sudo: false
cache:

View File

@@ -1,30 +1,49 @@
build: off
cache:
- c:\php -> appveyor.yml
- c:\php5 -> appveyor.yml
- c:\php7 -> appveyor.yml
- '%LOCALAPPDATA%\Composer\files -> appveyor.yml'
clone_folder: c:\projects\dibi
services:
- mssql2012sp1
- mssql2014
- mysql
init:
- SET PATH=c:\php;%PATH%
- SET PHP=1
- SET PATH=c:\php5;%PATH%
- SET ANSICON=121x90 (121x90)
install:
# Install PHP
- IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php)
- IF %PHP%==1 cd c:\php
# Install PHP 5
- IF EXIST c:\php5 (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php5
- IF %PHP%==1 cd c:\php5
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-5.6.14-Win32-VC11-x86.zip
- IF %PHP%==1 7z x php-5.6.14-Win32-VC11-x86.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
- IF %PHP%==1 appveyor DownloadFile https://files.nette.org/misc/php-sqlsrv.zip
- IF %PHP%==1 7z x php-sqlsrv.zip >nul
- IF %PHP%==1 copy SQLSRV\php_sqlsrv_56_ts.dll ext\php_sqlsrv_ts.dll
- IF %PHP%==1 copy SQLSRV\php_pdo_sqlsrv_56_ts.dll ext\php_pdo_sqlsrv_ts.dll
- IF %PHP%==1 del /Q *.zip
# Install PHP 7
- IF EXIST c:\php7 (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php7
- IF %PHP%==1 cd c:\php7
- IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-7.0.3-Win32-VC14-x86.zip
- IF %PHP%==1 7z x php-7.0.3-Win32-VC14-x86.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 appveyor DownloadFile https://files.nette.org/misc/php-sqlsrv.zip
- IF %PHP%==1 7z x php-sqlsrv.zip >nul
- IF %PHP%==1 copy SQLSRV\php_sqlsrv_7_ts.dll ext\php_sqlsrv_ts.dll
- IF %PHP%==1 del /Q *.zip
- cd c:\projects\dibi
# Install Nette Tester
- cd c:\projects\dibi
- appveyor DownloadFile https://getcomposer.org/composer.phar
- php composer.phar install --prefer-dist --no-interaction --no-progress
@@ -32,7 +51,8 @@ install:
- copy tests\databases.appveyor.ini tests\databases.ini
test_script:
- vendor\bin\tester tests -s -p php -c tests\php-win.ini
- vendor\bin\tester tests -s -p c:\php5\php -c tests\php5-win.ini
- vendor\bin\tester tests -s -p c:\php7\php -c tests\php7-win.ini
on_failure:
# Print *.actual content

View File

@@ -15,10 +15,10 @@
},
"require-dev": {
"tracy/tracy": "~2.2",
"nette/tester": "~1.3"
"nette/tester": "~1.7"
},
"replace": {
"dg/dibi": "self.version"
"dg/dibi": "*"
},
"autoload": {
"classmap": ["src/"],

View File

@@ -1,27 +1,31 @@
How to contribute & use the issue tracker
=========================================
The issue tracker is the preferred channel for bug reports, features requests
and submitting pull requests, but please respect the following restrictions:
Dibi welcomes your contributions. There are several ways to help out:
* Please **do not** use the issue tracker for personal support requests (use
[dibi forum](https://forum.dibiphp.com) or [Stack Overflow](http://stackoverflow.com)).
* Create an issue on GitHub, if you have found a bug
* Write test cases for open bug issues
* Write fixes for open bug/feature issues, preferably with test cases included
* Contribute to the documentation
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
Issues
------
* Use the GitHub **issue search** &mdash; check if the issue has already been
reported.
Please **do not use the issue tracker to ask questions**. We will be happy to help you
on [Dibi forum](https://forum.dibiphp.com).
A good **bug report** shouldn't leave others needing to chase you up for more
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report.
**Feature requests** are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature.
We welcome **pull requests**. If you'd like to contribute, please take a moment
to [read the guidelines](https://nette.org/en/contributing) in order to make
the contribution process easy and effective for everyone involved.
Contributing
------------
Thanks!
The best way to propose a feature is to discuss your ideas on [Dibi forum](https://forum.dibiphp.com) before implementing them.
Please do not fix whitespace, format code, or make a purely cosmetic patch.
Thanks! :heart:

View File

@@ -112,6 +112,22 @@ try {
echo "</p>\n";
// connects to MS SQL
echo '<p>Connecting to MS SQL: ';
try {
dibi::connect([
'driver' => 'mssql',
'host' => 'localhost',
'username' => 'root',
'password' => 'xxx',
]);
echo 'OK';
} catch (Dibi\Exception $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
echo "</p>\n";
// connects to SQLSRV
echo '<p>Connecting to Microsoft SQL Server: ';
try {

View File

@@ -7,6 +7,7 @@
namespace Dibi\Bridges\Nette;
use Dibi;
use Nette;
@@ -47,7 +48,10 @@ class DibiExtension22 extends Nette\DI\CompilerExtension
}
if ($useProfiler) {
$panel = $container->addDefinition($this->prefix('panel'))
->setClass('Dibi\Bridges\Tracy\Panel');
->setClass('Dibi\Bridges\Tracy\Panel', [
isset($config['explain']) ? $config['explain'] : TRUE,
isset($config['filter']) && $config['filter'] === FALSE ? Dibi\Event::ALL : Dibi\Event::QUERY,
]);
$connection->addSetup([$panel, 'register'], [$connection]);
}
}

View File

@@ -110,7 +110,7 @@ class Panel implements Tracy\IBarPanel
$backup = [$event->connection->onEvent, \dibi::$numOfQueries, \dibi::$totalTime];
$event->connection->onEvent = NULL;
$cmd = is_string($this->explain) ? $this->explain : ($event->connection->getConfig('driver') === 'oracle' ? 'EXPLAIN PLAN FOR' : 'EXPLAIN');
$explain = Helpers::dump($event->connection->nativeQuery("$cmd $event->sql"), TRUE);
$explain = Helpers::dump(@$event->connection->nativeQuery("$cmd $event->sql"), TRUE);
} catch (Dibi\Exception $e) {
}
list($event->connection->onEvent, \dibi::$numOfQueries, \dibi::$totalTime) = $backup;

View File

@@ -289,7 +289,7 @@ class Connection
* @param array
* @return string
*/
private function translateArgs($args)
protected function translateArgs($args)
{
$this->connected || $this->connect();
if (!$this->translator) {
@@ -555,7 +555,7 @@ class Connection
/**
* Executes SQL query and fetch result - shortcut for query() & fetch().
* @param array|mixed one or more arguments
* @return Row
* @return Row|bool
* @throws Exception
*/
public function fetch($args)
@@ -581,7 +581,7 @@ class Connection
/**
* Executes SQL query and fetch first column - shortcut for query() & fetchSingle().
* @param array|mixed one or more arguments
* @return string
* @return string|bool
* @throws Exception
*/
public function fetchSingle($args)
@@ -594,7 +594,7 @@ class Connection
/**
* Executes SQL query and fetch pairs - shortcut for query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @return array
* @throws Exception
*/
public function fetchPairs($args)

View File

@@ -55,4 +55,18 @@ class DateTime extends \DateTime
return $this->format('Y-m-d H:i:s');
}
public function __wakeup()
{
if (isset($this->fix, $this->fix[1])) {
$this->__construct($this->fix[0], new \DateTimeZone($this->fix[1]));
unset($this->fix);
} elseif (isset($this->fix)) {
$this->__construct($this->fix[0]);
unset($this->fix);
} else {
parent::__wakeup();
}
}
}

View File

@@ -78,9 +78,9 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
];
if (empty($config['persistent'])) {
$this->connection = ibase_connect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
$this->connection = @ibase_connect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
} else {
$this->connection = ibase_pconnect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
$this->connection = @ibase_pconnect($config['database'], $config['username'], $config['password'], $config['charset'], $config['buffers']); // intentionally @
}
if (!is_resource($this->connection)) {
@@ -96,7 +96,7 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function disconnect()
{
ibase_close($this->connection);
@ibase_close($this->connection); // @ - connection can be already disconnected
}
@@ -268,7 +268,7 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
public function escapeIdentifier($value)
{
return $value;
return '"' . str_replace('"', '""', $value). '"';
}
@@ -333,9 +333,9 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($limit >= 0 && $offset > 0) {
// see http://scott.yang.id.au/2004/01/limit-in-select-statements-in-firebird/
$sql = 'SELECT FIRST ' . (int) $limit . ($offset > 0 ? ' SKIP ' . (int) $offset : '') . ' * FROM (' . $sql . ')';
if ($limit > 0 || $offset > 0) {
// http://www.firebirdsql.org/refdocs/langrefupd20-select.html
$sql = 'SELECT ' . ($limit > 0 ? 'FIRST ' . (int) $limit : '') . ($offset > 0 ? ' SKIP ' . (int) $offset : '') . ' * FROM (' . $sql . ')';
}
}
@@ -370,7 +370,7 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function fetch($assoc)
{
$result = $assoc ? ibase_fetch_assoc($this->resultSet, IBASE_TEXT) : ibase_fetch_row($this->resultSet, IBASE_TEXT); // intentionally @
$result = $assoc ? @ibase_fetch_assoc($this->resultSet, IBASE_TEXT) : @ibase_fetch_row($this->resultSet, IBASE_TEXT); // intentionally @
if (ibase_errcode()) {
if (ibase_errcode() == self::ERROR_EXCEPTION_THROWN) {
@@ -378,7 +378,7 @@ class FirebirdDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
throw new Dibi\ProcedureException($match[3], $match[1], $match[2]);
} else {
throw new Dibi\DriverException($msg, ibase_errcode());
throw new Dibi\DriverException(ibase_errmsg(), ibase_errcode());
}
}

View File

@@ -0,0 +1,386 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
namespace Dibi\Drivers;
use Dibi;
/**
* The dibi driver for MS SQL database.
*
* Driver options:
* - host => the MS SQL server host name. It can also include a port number (hostname:port)
* - username (or user)
* - password (or pass)
* - database => the database name to select
* - persistent (bool) => try to find a persistent link?
* - resource (resource) => existing connection resource
* - lazy, profiler, result, substitutes, ... => see Dibi\Connection options
*/
class MsSqlDriver implements Dibi\Driver, Dibi\ResultDriver
{
use Dibi\Strict;
/** @var resource Connection resource */
private $connection;
/** @var resource Resultset resource */
private $resultSet;
/** @var bool */
private $autoFree = TRUE;
/**
* @throws Dibi\NotSupportedException
*/
public function __construct()
{
if (!extension_loaded('mssql')) {
throw new Dibi\NotSupportedException("PHP extension 'mssql' is not loaded.");
}
}
/**
* Connects to a database.
* @return void
* @throws Dibi\Exception
*/
public function connect(array & $config)
{
if (isset($config['resource'])) {
$this->connection = $config['resource'];
} elseif (empty($config['persistent'])) {
$this->connection = @mssql_connect($config['host'], $config['username'], $config['password'], TRUE); // intentionally @
} else {
$this->connection = @mssql_pconnect($config['host'], $config['username'], $config['password']); // intentionally @
}
if (!is_resource($this->connection)) {
throw new Dibi\DriverException("Can't connect to DB.");
}
if (isset($config['database']) && !@mssql_select_db($this->escapeIdentifier($config['database']), $this->connection)) { // intentionally @
throw new Dibi\DriverException("Can't select DB '$config[database]'.");
}
}
/**
* Disconnects from a database.
* @return void
*/
public function disconnect()
{
@mssql_close($this->connection); // @ - connection can be already disconnected
}
/**
* Executes the SQL query.
* @param string SQL statement.
* @return Dibi\ResultDriver|NULL
* @throws Dibi\DriverException
*/
public function query($sql)
{
$res = @mssql_query($sql, $this->connection); // intentionally @
if ($res === FALSE) {
throw new Dibi\DriverException(mssql_get_last_message(), 0, $sql);
} elseif (is_resource($res)) {
return $this->createResultDriver($res);
}
}
/**
* Gets the number of affected rows by the last INSERT, UPDATE or DELETE query.
* @return int|FALSE number of rows or FALSE on error
*/
public function getAffectedRows()
{
return mssql_rows_affected($this->connection);
}
/**
* Retrieves the ID generated for an AUTO_INCREMENT column by the previous INSERT query.
* @return int|FALSE int on success or FALSE on failure
*/
public function getInsertId($sequence)
{
$res = mssql_query('SELECT @@IDENTITY', $this->connection);
if (is_resource($res)) {
$row = mssql_fetch_row($res);
return $row[0];
}
return FALSE;
}
/**
* Begins a transaction (if supported).
* @param string optional savepoint name
* @return void
* @throws Dibi\DriverException
*/
public function begin($savepoint = NULL)
{
$this->query('BEGIN TRANSACTION');
}
/**
* Commits statements in a transaction.
* @param string optional savepoint name
* @return void
* @throws Dibi\DriverException
*/
public function commit($savepoint = NULL)
{
$this->query('COMMIT');
}
/**
* Rollback changes in a transaction.
* @param string optional savepoint name
* @return void
* @throws Dibi\DriverException
*/
public function rollback($savepoint = NULL)
{
$this->query('ROLLBACK');
}
/**
* Returns the connection resource.
* @return mixed
*/
public function getResource()
{
return is_resource($this->connection) ? $this->connection : NULL;
}
/**
* Returns the connection reflector.
* @return Dibi\Reflector
*/
public function getReflector()
{
return new MsSqlReflector($this);
}
/**
* Result set driver factory.
* @param resource
* @return Dibi\ResultDriver
*/
public function createResultDriver($resource)
{
$res = clone $this;
$res->resultSet = $resource;
return $res;
}
/********************* SQL ****************d*g**/
/**
* Encodes data for use in a SQL statement.
* @param mixed value
* @return string encoded value
*/
public function escapeText($value)
{
return "'" . str_replace("'", "''", $value) . "'";
}
public function escapeBinary($value)
{
return "'" . str_replace("'", "''", $value) . "'";
}
public function escapeIdentifier($value)
{
// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
return '[' . str_replace(['[', ']'], ['[[', ']]'], $value) . ']';
}
public function escapeBool($value)
{
return $value ? 1 : 0;
}
public function escapeDate($value)
{
if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
$value = new Dibi\DateTime($value);
}
return $value->format("'Y-m-d'");
}
public function escapeDateTime($value)
{
if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
$value = new Dibi\DateTime($value);
}
return $value->format("'Y-m-d H:i:s'");
}
/**
* Encodes string for use in a LIKE statement.
* @param string
* @param int
* @return string
*/
public function escapeLike($value, $pos)
{
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
}
/**
* Decodes data from result set.
* @param string
* @return string
*/
public function unescapeBinary($value)
{
return $value;
}
/** @deprecated */
public function escape($value, $type)
{
trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
return Dibi\Helpers::escape($this, $value, $type);
}
/**
* Injects LIMIT/OFFSET to the SQL query.
* @return void
*/
public function applyLimit(& $sql, $limit, $offset)
{
if ($offset) {
throw new Dibi\NotSupportedException('Offset is not supported by this database.');
} elseif ($limit < 0) {
throw new Dibi\NotSupportedException('Negative offset or limit.');
} elseif ($limit !== NULL) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
}
}
/********************* result set ****************d*g**/
/**
* Automatically frees the resources allocated for this result set.
* @return void
*/
public function __destruct()
{
$this->autoFree && $this->getResultResource() && $this->free();
}
/**
* Returns the number of rows in a result set.
* @return int
*/
public function getRowCount()
{
return mssql_num_rows($this->resultSet);
}
/**
* Fetches the row at current position and moves the internal cursor to the next position.
* @param bool TRUE for associative array, FALSE for numeric
* @return array array on success, nonarray if no next record
*/
public function fetch($assoc)
{
return mssql_fetch_array($this->resultSet, $assoc ? MSSQL_ASSOC : MSSQL_NUM);
}
/**
* Moves cursor position without fetching row.
* @param int the 0-based cursor pos to seek to
* @return boolean TRUE on success, FALSE if unable to seek to specified record
*/
public function seek($row)
{
return mssql_data_seek($this->resultSet, $row);
}
/**
* Frees the resources allocated for this result set.
* @return void
*/
public function free()
{
mssql_free_result($this->resultSet);
$this->resultSet = NULL;
}
/**
* Returns metadata for all columns in a result set.
* @return array
*/
public function getResultColumns()
{
$count = mssql_num_fields($this->resultSet);
$columns = [];
for ($i = 0; $i < $count; $i++) {
$row = (array) mssql_fetch_field($this->resultSet, $i);
$columns[] = [
'name' => $row['name'],
'fullname' => $row['column_source'] ? $row['column_source'] . '.' . $row['name'] : $row['name'],
'table' => $row['column_source'],
'nativetype' => $row['type'],
];
}
return $columns;
}
/**
* Returns the result set resource.
* @return mixed
*/
public function getResultResource()
{
$this->autoFree = FALSE;
return is_resource($this->resultSet) ? $this->resultSet : NULL;
}
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* This file is part of the "dibi" - smart database abstraction layer.
* Copyright (c) 2005 David Grudl (https://davidgrudl.com)
*/
namespace Dibi\Drivers;
use Dibi;
/**
* The dibi reflector for MS SQL databases.
* @internal
*/
class MsSqlReflector implements Dibi\Reflector
{
use Dibi\Strict;
/** @var Dibi\Driver */
private $driver;
public function __construct(Dibi\Driver $driver)
{
$this->driver = $driver;
}
/**
* Returns list of tables.
* @return array
*/
public function getTables()
{
$res = $this->driver->query('
SELECT TABLE_NAME, TABLE_TYPE
FROM INFORMATION_SCHEMA.TABLES
');
$tables = [];
while ($row = $res->fetch(FALSE)) {
$tables[] = [
'name' => $row[0],
'view' => isset($row[1]) && $row[1] === 'VIEW',
];
}
return $tables;
}
/**
* Returns count of rows in a table
* @param string
* @return int
*/
public function getTableCount($table, $fallback = TRUE)
{
if (empty($table)) {
return FALSE;
}
$result = $this->driver->query("
SELECT MAX(rowcnt)
FROM sys.sysindexes
WHERE id=OBJECT_ID({$this->driver->escapeIdentifier($table)})
");
$row = $result->fetch(FALSE);
if (!is_array($row) || count($row) < 1) {
if ($fallback) {
$row = $this->driver->query("SELECT COUNT(*) FROM {$this->driver->escapeIdentifier($table)}")->fetch(FALSE);
$count = intval($row[0]);
} else {
$count = FALSE;
}
} else {
$count = intval($row[0]);
}
return $count;
}
/**
* Returns metadata for all columns in a table.
* @param string
* @return array
*/
public function getColumns($table)
{
$res = $this->driver->query("
SELECT * FROM
INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = {$this->driver->escapeText($table)}
ORDER BY TABLE_NAME, ORDINAL_POSITION
");
$columns = [];
while ($row = $res->fetch(TRUE)) {
$size = FALSE;
$type = strtoupper($row['DATA_TYPE']);
$size_cols = [
'DATETIME' => 'DATETIME_PRECISION',
'DECIMAL' => 'NUMERIC_PRECISION',
'CHAR' => 'CHARACTER_MAXIMUM_LENGTH',
'NCHAR' => 'CHARACTER_OCTET_LENGTH',
'NVARCHAR' => 'CHARACTER_OCTET_LENGTH',
'VARCHAR' => 'CHARACTER_OCTET_LENGTH',
];
if (isset($size_cols[$type])) {
if ($size_cols[$type]) {
$size = $row[$size_cols[$type]];
}
}
$columns[] = [
'name' => $row['COLUMN_NAME'],
'table' => $table,
'nativetype' => $type,
'size' => $size,
'unsigned' => NULL,
'nullable' => $row['IS_NULLABLE'] === 'YES',
'default' => $row['COLUMN_DEFAULT'],
'autoincrement' => FALSE,
'vendor' => $row,
];
}
return $columns;
}
/**
* Returns metadata for all indexes in a table.
* @param string
* @return array
*/
public function getIndexes($table)
{
$res = $this->driver->query(
"SELECT ind.name index_name, ind.index_id, ic.index_column_id,
col.name column_name, ind.is_unique, ind.is_primary_key
FROM sys.indexes ind
INNER JOIN sys.index_columns ic ON
(ind.object_id = ic.object_id AND ind.index_id = ic.index_id)
INNER JOIN sys.columns col ON
(ic.object_id = col.object_id and ic.column_id = col.column_id)
INNER JOIN sys.tables t ON
(ind.object_id = t.object_id)
WHERE t.name = {$this->driver->escapeText($table)}
AND t.is_ms_shipped = 0
ORDER BY
t.name, ind.name, ind.index_id, ic.index_column_id
");
$indexes = [];
while ($row = $res->fetch(TRUE)) {
$index_name = $row['index_name'];
if (!isset($indexes[$index_name])) {
$indexes[$index_name] = [];
$indexes[$index_name]['name'] = $index_name;
$indexes[$index_name]['unique'] = (bool) $row['is_unique'];
$indexes[$index_name]['primary'] = (bool) $row['is_primary_key'];
$indexes[$index_name]['columns'] = [];
}
$indexes[$index_name]['columns'][] = $row['column_name'];
}
return array_values($indexes);
}
/**
* Returns metadata for all foreign keys in a table.
* @param string
* @return array
*/
public function getForeignKeys($table)
{
$res = $this->driver->query("
SELECT f.name AS foreign_key,
OBJECT_NAME(f.parent_object_id) AS table_name,
COL_NAME(fc.parent_object_id,
fc.parent_column_id) AS column_name,
OBJECT_NAME (f.referenced_object_id) AS reference_table_name,
COL_NAME(fc.referenced_object_id,
fc.referenced_column_id) AS reference_column_name,
fc.*
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
WHERE OBJECT_NAME(f.parent_object_id) = {$this->driver->escapeText($table)}
");
$keys = [];
while ($row = $res->fetch(TRUE)) {
$key_name = $row['foreign_key'];
if (!isset($keys[$key_name])) {
$keys[$key_name]['name'] = $row['foreign_key']; // foreign key name
$keys[$key_name]['local'] = [$row['column_name']]; // local columns
$keys[$key_name]['table'] = $row['reference_table_name']; // referenced table
$keys[$key_name]['foreign'] = [$row['reference_column_name']]; // referenced columns
$keys[$key_name]['onDelete'] = FALSE;
$keys[$key_name]['onUpdate'] = FALSE;
} else {
$keys[$key_name]['local'][] = $row['column_name']; // local columns
$keys[$key_name]['foreign'][] = $row['reference_column_name']; // referenced columns
}
}
return array_values($keys);
}
}

View File

@@ -139,7 +139,7 @@ class MySqlDriver implements Dibi\Driver, Dibi\ResultDriver
*/
public function disconnect()
{
mysql_close($this->connection);
@mysql_close($this->connection); // @ - connection can be already disconnected
}

View File

@@ -138,7 +138,7 @@ class MySqliDriver implements Dibi\Driver, Dibi\ResultDriver
*/
public function disconnect()
{
mysqli_close($this->connection);
@mysqli_close($this->connection); // @ - connection can be already disconnected
}

View File

@@ -88,7 +88,7 @@ class OdbcDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function disconnect()
{
odbc_close($this->connection);
@odbc_close($this->connection); // @ - connection can be already disconnected
}

View File

@@ -44,6 +44,9 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
/** @var string Date and datetime format */
private $fmtDate, $fmtDateTime;
/** @var int|FALSE Number of affected rows */
private $affectedRows = FALSE;
/**
* @throws Dibi\NotSupportedException
@@ -92,7 +95,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function disconnect()
{
oci_close($this->connection);
@oci_close($this->connection); // @ - connection can be already disconnected
}
@@ -104,6 +107,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function query($sql)
{
$this->affectedRows = FALSE;
$res = oci_parse($this->connection, $sql);
if ($res) {
@oci_execute($res, $this->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT);
@@ -112,6 +116,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
throw self::createException($err['message'], $err['code'], $sql);
} elseif (is_resource($res)) {
$this->affectedRows = oci_num_rows($res);
return $this->createResultDriver($res);
}
} else {
@@ -147,7 +152,7 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function getAffectedRows()
{
throw new Dibi\NotImplementedException;
return $this->affectedRows;
}
@@ -461,7 +466,20 @@ class OracleDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function getColumns($table)
{
throw new Dibi\NotImplementedException;
$res = $this->query('SELECT * FROM "ALL_TAB_COLUMNS" WHERE "TABLE_NAME" = ' . $this->escapeText($table));
$columns = [];
while ($row = $res->fetch(TRUE)) {
$columns[] = [
'table' => $row['TABLE_NAME'],
'name' => $row['COLUMN_NAME'],
'nativetype' => $row['DATA_TYPE'],
'size' => isset($row['DATA_LENGTH']) ? $row['DATA_LENGTH'] : NULL,
'nullable' => $row['NULLABLE'] === 'Y',
'default' => $row['DATA_DEFAULT'],
'vendor' => $row,
];
}
return $columns;
}

View File

@@ -291,6 +291,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
return '[' . strtr($value, '[]', ' ') . ']';
case 'odbc':
case 'mssql':
return '[' . str_replace(['[', ']'], ['[[', ']]'], $value) . ']';
case 'dblib':
@@ -360,6 +361,7 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
case 'odbc':
case 'mssql':
case 'dblib':
case 'sqlsrv':
$value = strtr($value, ["'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]']);
@@ -437,13 +439,15 @@ class PdoDriver implements Dibi\Driver, Dibi\ResultDriver
}
break;
case 'mssql':
case 'sqlsrv':
case 'dblib':
if (version_compare($this->serverVersion, '11.0') >= 0) { // 11 == SQL Server 2012
if ($limit !== NULL || $offset) {
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
$sql .= ' OFFSET ' . (int) $offset . ' ROWS '
. 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY';
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
if ($limit !== NULL) {
$sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit);
} elseif ($offset) {
$sql = sprintf('%s OFFSET %d ROWS', rtrim($sql), $offset);
}
break;
}

View File

@@ -100,7 +100,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
}
if (isset($config['schema'])) {
$this->query('SET search_path TO "' . $config['schema'] . '"');
$this->query('SET search_path TO "' . implode('", "', (array) $config['schema']) . '"');
}
}
@@ -111,7 +111,7 @@ class PostgreDriver implements Dibi\Driver, Dibi\ResultDriver, Dibi\Reflector
*/
public function disconnect()
{
pg_close($this->connection);
@pg_close($this->connection); // @ - connection can be already disconnected
}

View File

@@ -72,12 +72,17 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
$this->connection = $config['resource'];
} else {
// Default values
if (!isset($config['options']['CharacterSet'])) {
$config['options']['CharacterSet'] = 'UTF-8';
}
$options = $config['options'];
$this->connection = sqlsrv_connect($config['host'], (array) $config['options']);
// Default values
if (!isset($options['CharacterSet'])) {
$options['CharacterSet'] = 'UTF-8';
}
$options['PWD'] = (string) $options['PWD'];
$options['UID'] = (string) $options['UID'];
$options['Database'] = (string) $options['Database'];
$this->connection = sqlsrv_connect($config['host'], $options);
}
if (!is_resource($this->connection)) {
@@ -94,7 +99,7 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
*/
public function disconnect()
{
sqlsrv_close($this->connection);
@sqlsrv_close($this->connection); // @ - connection can be already disconnected
}
@@ -136,7 +141,7 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
*/
public function getInsertId($sequence)
{
$res = sqlsrv_query($this->connection, 'SELECT @@IDENTITY');
$res = sqlsrv_query($this->connection, 'SELECT SCOPE_IDENTITY()');
if (is_resource($res)) {
$row = sqlsrv_fetch_array($res, SQLSRV_FETCH_NUMERIC);
return $row[0];
@@ -311,13 +316,15 @@ class SqlsrvDriver implements Dibi\Driver, Dibi\ResultDriver
throw new Dibi\NotSupportedException('Offset is not supported by this database.');
} elseif ($limit !== NULL) {
$sql = 'SELECT TOP ' . (int) $limit . ' * FROM (' . $sql . ') t';
$sql = sprintf('SELECT TOP (%d) * FROM (%s) t', $limit, $sql);
}
} elseif ($limit !== NULL || $offset) {
} elseif ($limit !== NULL) {
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
$sql .= ' OFFSET ' . (int) $offset . ' ROWS '
. 'FETCH NEXT ' . (int) $limit . ' ROWS ONLY';
$sql = sprintf('%s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY', rtrim($sql), $offset, $limit);
} elseif ($offset) {
// requires ORDER BY, see https://technet.microsoft.com/en-us/library/gg699618(v=sql.110).aspx
$sql = sprintf('%s OFFSET %d ROWS', rtrim($sql), $offset);
}
}

View File

@@ -34,7 +34,7 @@ class SqlsrvReflector implements Dibi\Reflector
*/
public function getTables()
{
$res = $this->driver->query('SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES');
$res = $this->driver->query("SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE [TABLE_SCHEMA] = 'dbo'");
$tables = [];
while ($row = $res->fetch(FALSE)) {
$tables[] = [
@@ -105,19 +105,19 @@ class SqlsrvReflector implements Dibi\Reflector
*/
public function getIndexes($table)
{
$keyUsagesRes = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = {$this->driver->escapeText($table)}");
$keyUsagesRes = $this->driver->query(sprintf("EXEC [sys].[sp_helpindex] @objname = N%s", $this->driver->escapeText($table)));
$keyUsages = [];
while ($row = $keyUsagesRes->fetch(TRUE)) {
$keyUsages[$row['CONSTRAINT_NAME']][(int) $row['ORDINAL_POSITION'] - 1] = $row['COLUMN_NAME'];
$keyUsages[$row['index_name']] = explode(',', $row['index_keys']);
}
$res = $this->driver->query("SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = {$this->driver->escapeText($table)}");
$res = $this->driver->query("SELECT [i].* FROM [sys].[indexes] [i] INNER JOIN [sys].[tables] [t] ON [i].[object_id] = [t].[object_id] WHERE [t].[name] = {$this->driver->escapeText($table)}");
$indexes = [];
while ($row = $res->fetch(TRUE)) {
$indexes[$row['CONSTRAINT_NAME']]['name'] = $row['CONSTRAINT_NAME'];
$indexes[$row['CONSTRAINT_NAME']]['unique'] = $row['CONSTRAINT_TYPE'] === 'UNIQUE';
$indexes[$row['CONSTRAINT_NAME']]['primary'] = $row['CONSTRAINT_TYPE'] === 'PRIMARY KEY';
$indexes[$row['CONSTRAINT_NAME']]['columns'] = isset($keyUsages[$row['CONSTRAINT_NAME']]) ? $keyUsages[$row['CONSTRAINT_NAME']] : [];
$indexes[$row['name']]['name'] = $row['name'];
$indexes[$row['name']]['unique'] = $row['is_unique'] === 1;
$indexes[$row['name']]['primary'] = $row['is_primary_key'] === 1;
$indexes[$row['name']]['columns'] = isset($keyUsages[$row['name']]) ? $keyUsages[$row['name']] : [];
}
return array_values($indexes);
}

View File

@@ -25,6 +25,7 @@ namespace Dibi;
* @method Fluent innerJoin(...$table)
* @method Fluent rightJoin(...$table)
* @method Fluent outerJoin(...$table)
* @method Fluent as(...$field)
* @method Fluent on(...$cond)
* @method Fluent using(...$cond)
*/
@@ -180,7 +181,7 @@ class Fluent implements IDataSource
return $this;
} elseif (is_string($arg) && preg_match('#^[a-z:_][a-z0-9_.:]*\z#i', $arg)) { // identifier
$args = ['%n', $arg];
$args = [$clause === 'AS' ? '%N' : '%n', $arg];
} elseif (is_array($arg) || ($arg instanceof \Traversable && !$arg instanceof self)) { // any array
if (isset(self::$modifiers[$clause])) {

View File

@@ -183,7 +183,7 @@ class Helpers
static $patterns = [
'^_' => Type::TEXT, // PostgreSQL arrays
'BYTEA|BLOB|BIN' => Type::BINARY,
'TEXT|CHAR|POINT|INTERVAL' => Type::TEXT,
'TEXT|CHAR|POINT|INTERVAL|STRING' => Type::TEXT,
'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT|^TINY$' => Type::INTEGER,
'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => Type::FLOAT,
'^TIME$' => Type::TIME,

View File

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

View File

@@ -38,7 +38,7 @@ class Row implements \ArrayAccess, \IteratorAggregate, \Countable
{
$time = $this[$key];
if (!$time instanceof DateTime) {
if ((int) $time === 0 && substr((string) $time, 0, 3) !== '00:') { // '', NULL, FALSE, '0000-00-00', ...
if (!$time || substr((string) $time, 0, 3) === '000') { // '', NULL, FALSE, '0000-00-00', ...
return NULL;
}
$time = new DateTime($time);

View File

@@ -225,7 +225,7 @@ final class Translator
case 'n': // key, key, ... identifier names
foreach ($value as $k => $v) {
if (is_string($k)) {
$vx[] = $this->identifiers->$k . (empty($v) ? '' : ' AS ' . $this->identifiers->$v);
$vx[] = $this->identifiers->$k . (empty($v) ? '' : ' AS ' . $this->driver->escapeIdentifier($v));
} else {
$pair = explode('%', $v, 2); // split into identifier & modifier
$vx[] = $this->identifiers->{$pair[0]};
@@ -380,9 +380,12 @@ final class Translator
}
case 'by':
case 'n': // identifier name
case 'n': // composed identifier name
return $this->identifiers->$value;
case 'N': // identifier name
return $this->driver->escapeIdentifier($value);
case 'ex':
case 'sql': // preserve as dibi-SQL (TODO: leave only %ex)
$value = (string) $value;

View File

@@ -22,8 +22,8 @@ class dibi
/** version */
const
VERSION = '3.0.1',
REVISION = 'released on 2015-12-16';
VERSION = '3.0.7',
REVISION = 'released on 2017-01-04';
/** sorting order */
const
@@ -254,7 +254,7 @@ class dibi
/**
* Executes SQL query and fetch pairs - Monostate for Dibi\Connection::query() & fetchPairs().
* @param array|mixed one or more arguments
* @return string
* @return array
* @throws Dibi\Exception
*/
public static function fetchPairs($args)

View File

@@ -13,8 +13,6 @@ namespace Dibi;
*/
class Exception extends \Exception
{
use Strict;
/** @var string|NULL */
private $sql;
@@ -66,7 +64,6 @@ class DriverException extends Exception
*/
class PcreException extends Exception
{
use Strict;
public function __construct($message = '%msg.')
{

View File

@@ -26,6 +26,8 @@ spl_autoload_register(function ($class) {
'Dibi\Drivers\FirebirdDriver' => 'Drivers/FirebirdDriver.php',
'Dibi\Drivers\SqlsrvDriver' => 'Drivers/SqlsrvDriver.php',
'Dibi\Drivers\SqlsrvReflector' => 'Drivers/SqlsrvReflector.php',
'Dibi\Drivers\MsSqlDriver' => 'Drivers/MsSqlDriver.php',
'Dibi\Drivers\MsSqlReflector' => 'Drivers/MsSqlReflector.php',
'Dibi\Drivers\MySqlDriver' => 'Drivers/MySqlDriver.php',
'Dibi\Drivers\MySqliDriver' => 'Drivers/MySqliDriver.php',
'Dibi\Drivers\MySqlReflector' => 'Drivers/MySqlReflector.php',
@@ -84,6 +86,8 @@ spl_autoload_register(function ($class) {
'DibiLiteral' => 'Dibi\Literal',
'DibiMsSql2005Driver' => 'Dibi\Drivers\SqlsrvDriver',
'DibiMsSql2005Reflector' => 'Dibi\Drivers\SqlsrvReflector',
'DibiMsSqlDriver' => 'Dibi\Drivers\MsSqlDriver',
'DibiMsSqlReflector' => 'Dibi\Drivers\MsSqlReflector',
'DibiMySqlDriver' => 'Dibi\Drivers\MySqlDriver',
'DibiMySqliDriver' => 'Dibi\Drivers\MySqliDriver',
'DibiMySqlReflector' => 'Dibi\Drivers\MySqlReflector',

4
tests/.coveralls.yml Normal file
View File

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

View File

@@ -42,3 +42,48 @@ dsn = "odbc:Driver={Microsoft Access Driver (*.mdb)};Dbq=data/odbc.mdb"
username =
password =
system = odbc
;[sqlsrv 2008]
;driver = sqlsrv
;host = "(local)\SQL2008R2SP2"
;database = master
;username = sa
;password = "Password12!"
;system = sqlsrv
;[sqlsrv 2008-pdo]
;driver = pdo
;dsn = "sqlsrv:Server=(local)\SQL2008R2SP2;Database=master"
;username = sa
;password = "Password12!"
;system = sqlsrv
[sqlsrv 2012]
driver = sqlsrv
host = "(local)\SQL2012SP1"
database = master
username = sa
password = "Password12!"
system = sqlsrv
;[sqlsrv 2012-pdo]
;driver = pdo
;dsn = "sqlsrv:Server=(local)\SQL2012SP1;Database=master"
;username = sa
;password = "Password12!"
;system = sqlsrv
[sqlsrv 2014]
driver = sqlsrv
host = "(local)\SQL2014"
database = master
username = sa
password = "Password12!"
system = sqlsrv
;[sqlsrv 2014-pdo]
;driver = pdo
;dsn = "sqlsrv:Server=(local)\SQL2014;Database=master"
;username = sa
;password = "Password12!"
;system = sqlsrv

View File

@@ -57,6 +57,20 @@ username =
password =
system = odbc
[mssql]
driver = mssql
host = 127.0.0.1
username = dibi
password =
system = mssql
[mssql pdo]
driver = pdo
host = mssql:host=127.0.0.1;dbname=dibi_test
username = dibi
password =
system = mssql
[sqlsrv]
driver = sqlsrv
host = (local)

View File

@@ -36,3 +36,15 @@ test(function () use ($config) { // query string
Assert::same($config['driver'], $conn->getConfig('driver'));
Assert::type('Dibi\Driver', $conn->getDriver());
});
test(function () use ($config) {
$conn = new Connection($config);
Assert::true($conn->isConnected());
$conn->disconnect();
Assert::false($conn->isConnected());
$conn->disconnect();
Assert::false($conn->isConnected());
});

View File

@@ -14,7 +14,7 @@ $conn->loadFile(__DIR__ . "/data/$config[system].sql");
// fetch a single value
$res = $conn->query('SELECT [title] FROM [products]');
$res = $conn->query('SELECT [title] FROM [products] ORDER BY [product_id]');
Assert::same('Chair', $res->fetchSingle());
@@ -63,7 +63,7 @@ Assert::equal([
// more complex association array
function query($conn) {
return $conn->query($conn->getConfig('system') === 'odbc' ? '
return $conn->query(in_array($conn->getConfig('system'), ['odbc', 'sqlsrv']) ? '
SELECT products.title, customers.name, orders.amount
FROM ([products]
INNER JOIN [orders] ON [products.product_id] = [orders.product_id])

View File

@@ -40,28 +40,28 @@ $fluent = $conn->select('*')
->orderBy('customer_id');
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
);
$fluent->fetch();
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
);
$fluent->fetchSingle();
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
);
$fluent->fetchAll(0, 3);
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
);
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
);
@@ -69,16 +69,16 @@ Assert::same(
$fluent->limit(0);
$fluent->fetch();
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
);
$fluent->fetchSingle();
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
);
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
);
@@ -87,12 +87,12 @@ $fluent->removeClause('limit');
$fluent->removeClause('offset');
$fluent->fetch();
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
);
$fluent->fetchSingle();
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
);
Assert::same(

View File

@@ -28,7 +28,7 @@ Assert::equal([
// more complex association array
if ($config['system'] !== 'odbc') {
if (!in_array($config['system'], ['odbc', 'sqlsrv'])) {
$res = $conn->select(['products.title' => 'title', 'customers.name' => 'name'])->select('orders.amount')->as('amount')
->from('products')
->innerJoin('orders')->using('(product_id)')

View File

@@ -26,19 +26,19 @@ Assert::same(
(string) $fluent
);
$fluent->from('table')->as('tableAlias')
$fluent->from('table')->as('table.Alias')
->innerJoin('table1')->on('table.col = table1.col')
->innerJoin('table2')->on('table.col = table2.col');
Assert::same(
reformat('SELECT * , [a] , [b] AS [bAlias] , [c], [d], [e] , [d] FROM [table] AS [tableAlias] INNER JOIN [table1] ON table.col = table1.col INNER JOIN [table2] ON table.col = table2.col'),
reformat('SELECT * , [a] , [b] AS [bAlias] , [c], [d], [e] , [d] FROM [table] AS [table.Alias] INNER JOIN [table1] ON table.col = table1.col INNER JOIN [table2] ON table.col = table2.col'),
(string) $fluent
);
$fluent->from('anotherTable');
Assert::same(
reformat('SELECT * , [a] , [b] AS [bAlias] , [c], [d], [e] , [d] FROM [table] AS [tableAlias] INNER JOIN [table1] ON table.col = table1.col INNER JOIN [table2] ON table.col = table2.col , [anotherTable]'),
reformat('SELECT * , [a] , [b] AS [bAlias] , [c], [d], [e] , [d] FROM [table] AS [table.Alias] INNER JOIN [table1] ON table.col = table1.col INNER JOIN [table2] ON table.col = table2.col , [anotherTable]'),
(string) $fluent
);
@@ -94,6 +94,7 @@ $fluent = $conn->select('*')
Assert::same(
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',
'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',
]),
(string) $fluent

View File

@@ -1,7 +1,7 @@
<?php
/**
* @dataProvider ../databases.ini !=odbc
* @dataProvider ../databases.ini !=odbc, !=sqlsrv
*/
use Tester\Assert;
@@ -13,9 +13,9 @@ $conn->loadFile(__DIR__ . "/data/$config[system].sql");
$info = $conn->query('
SELECT products.product_id, orders.order_id, customers.name, products.product_id + 1 AS [xXx]
FROM products
INNER JOIN orders USING (product_id)
INNER JOIN customers USING (customer_id)
FROM ([products]
INNER JOIN [orders] ON [products.product_id] = [orders.product_id])
INNER JOIN [customers] ON [orders.customer_id] = [customers.customer_id]
')->getInfo();
@@ -25,7 +25,7 @@ Assert::same(
);
if ($config['driver'] !== 'sqlite3' && $config['driver'] !== 'pdo') {
if (!in_array($config['driver'], ['sqlite3', 'pdo', 'sqlsrv'])) {
Assert::same(
['products.product_id', 'orders.order_id', 'customers.name', 'xXx'],
$info->getColumnNames(TRUE)
@@ -36,18 +36,18 @@ if ($config['driver'] !== 'sqlite3' && $config['driver'] !== 'pdo') {
$columns = $info->getColumns();
Assert::same('product_id', $columns[0]->getName());
if ($config['driver'] !== 'sqlite3' && $config['driver'] !== 'pdo') {
if (!in_array($config['driver'], ['sqlite3', 'pdo', 'sqlsrv'])) {
Assert::same('products', $columns[0]->getTableName());
}
Assert::null($columns[0]->getVendorInfo('xxx'));
if ($config['system'] !== 'sqlite') {
if (!in_array($config['system'], ['sqlite', 'sqlsrv'])) {
Assert::same('i', $columns[0]->getType());
}
Assert::null($columns[0]->isNullable());
Assert::same('xXx', $columns[3]->getName());
Assert::null($columns[3]->getTableName());
if ($config['system'] !== 'sqlite') {
if (!in_array($config['system'], ['sqlite', 'sqlsrv'])) {
Assert::same('i', $columns[0]->getType());
}
Assert::null($columns[3]->isNullable());

View File

@@ -139,7 +139,7 @@ test(function () {
Assert::same(['col' => 1], $result->test(['col' => TRUE]));
Assert::same(['col' => 0], $result->test(['col' => FALSE]));
Assert::same(['col' => 0], $result->test(['col' => '']));
Assert::same(['col' => 0], @$result->test(['col' => ''])); // triggers warning in PHP 7.1
Assert::same(['col' => 0], $result->test(['col' => '0']));
Assert::same(['col' => 1], $result->test(['col' => '1']));
Assert::same(['col' => 10], $result->test(['col' => '10']));

View File

@@ -0,0 +1,28 @@
<?php
/**
* @dataProvider? ../databases.ini sqlsrv
*/
use Tester\Assert;
require __DIR__ . '/bootstrap.php';
$conn = new Dibi\Connection($config);
$conn->loadFile(__DIR__ . "/data/sqlsrv.insert.sql");
for ($i = 1; $i <= 5; $i++) {
$conn->query('INSERT INTO %n DEFAULT VALUES', 'aaa');
Assert::equal($i, $conn->getInsertId());
}
$conn->query('INSERT INTO %n DEFAULT VALUES', 'aab');
Assert::equal(1, $conn->getInsertId());
$conn->query(
'CREATE TRIGGER %n ON %n AFTER INSERT AS INSERT INTO %n DEFAULT VALUES',
'UpdAAB', 'aab', 'aaa'
);
$conn->query('INSERT INTO %n DEFAULT VALUES', 'aab');
Assert::equal(2, $conn->getInsertId());

View File

@@ -9,7 +9,10 @@ use Tester\Assert;
require __DIR__ . '/bootstrap.php';
$tests = function ($conn) {
$version = $conn->getDriver()->getResource()->getAttribute(PDO::ATTR_SERVER_VERSION);
$resource = $conn->getDriver()->getResource();
$version = is_resource($resource)
? sqlsrv_server_info($resource)['SQLServerVersion']
: $resource->getAttribute(PDO::ATTR_SERVER_VERSION);
// MsSQL2012+
if (version_compare($version, '11.0') >= 0) {
@@ -32,31 +35,43 @@ $tests = function ($conn) {
);
// Offset invalid
Assert::same(
'SELECT 1',
$conn->translate('SELECT 1 %ofs', -10)
Assert::error(
function () use ($conn) {
$conn->translate('SELECT 1 %ofs', -10);
},
'Dibi\NotSupportedException',
'Negative offset or limit.'
);
// Limit invalid
Assert::same(
'SELECT 1',
$conn->translate('SELECT 1 %lmt', -10)
Assert::error(
function () use ($conn) {
$conn->translate('SELECT 1 %lmt', -10);
},
'Dibi\NotSupportedException',
'Negative offset or limit.'
);
// Limit invalid, offset valid
Assert::same(
'SELECT 1',
$conn->translate('SELECT 1 %ofs %lmt', 10, -10)
Assert::error(
function () use ($conn) {
$conn->translate('SELECT 1 %ofs %lmt', 10, -10);
},
'Dibi\NotSupportedException',
'Negative offset or limit.'
);
// Limit valid, offset invalid
Assert::same(
'SELECT 1',
$conn->translate('SELECT 1 %ofs %lmt', -10, 10)
Assert::error(
function () use ($conn) {
$conn->translate('SELECT 1 %ofs %lmt', -10, 10);
},
'Dibi\NotSupportedException',
'Negative offset or limit.'
);
} else {
Assert::same(
'SELECT TOP 1 * FROM (SELECT 1) t',
'SELECT TOP (1) * FROM (SELECT 1) t',
$conn->translate('SELECT 1 %lmt', 1)
);

View File

@@ -141,6 +141,7 @@ Assert::same(
Assert::same(
reformat([
'odbc' => 'SELECT TOP 2 * FROM (SELECT * FROM [products] ) t',
'sqlsrv' => 'SELECT * FROM [products] OFFSET 0 ROWS FETCH NEXT 2 ROWS ONLY',
'SELECT * FROM [products] LIMIT 2',
]),
$conn->translate('SELECT * FROM [products] %lmt', 2)
@@ -153,7 +154,10 @@ if ($config['system'] === 'odbc') {
} else {
// with limit = 2, offset = 1
Assert::same(
reformat('SELECT * FROM [products] LIMIT 2 OFFSET 1'),
reformat([
'sqlsrv' => 'SELECT * FROM [products] OFFSET 1 ROWS FETCH NEXT 2 ROWS ONLY',
'SELECT * FROM [products] LIMIT 2 OFFSET 1'
]),
$conn->translate('SELECT * FROM [products] %lmt %ofs', 2, 1)
);
@@ -162,6 +166,7 @@ if ($config['system'] === 'odbc') {
reformat([
'mysql' => 'SELECT * FROM `products` LIMIT 18446744073709551615 OFFSET 50',
'postgre' => 'SELECT * FROM "products" OFFSET 50',
'sqlsrv' => 'SELECT * FROM [products] OFFSET 50 ROWS',
'SELECT * FROM [products] LIMIT -1 OFFSET 50',
]),
$conn->translate('SELECT * FROM [products] %ofs', 50)
@@ -224,6 +229,7 @@ if ($config['system'] === 'postgre') {
reformat([
'sqlite' => "SELECT * FROM products WHERE (title LIKE 'C%' ESCAPE '\\' AND title LIKE '%r' ESCAPE '\\') OR title LIKE '%a\n\\%\\_\\\\''\"%' ESCAPE '\\'",
'odbc' => "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n[%][_]\\''\"%'",
'sqlsrv' => "SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\n[%][_]\\''\"%'",
"SELECT * FROM products WHERE (title LIKE 'C%' AND title LIKE '%r') OR title LIKE '%a\\n\\%\\_\\\\\\\\\'\"%'",
]),
$conn->translate($args[0], $args[1], $args[2], $args[3])
@@ -274,7 +280,7 @@ $array2 = ['one', 'two', 'three'];
$array3 = [
'col1' => 'one',
'col2' => 'two',
'col3' => 'three',
'col3' => 'thr.ee',
];
$array4 = [
'a' => 12,
@@ -295,8 +301,8 @@ WHERE (`test`.`a` LIKE '1995-03-01'
OR `b2` IN ('1', '2', '3' )
OR `b3` IN ( )
OR `b4` IN ( 'one', 'two', 'three' )
OR `b5` IN (`col1` AS `one`, `col2` AS `two`, `col3` AS `three` )
OR `b6` IN ('one', 'two', 'three')
OR `b5` IN (`col1` AS `one`, `col2` AS `two`, `col3` AS `thr.ee` )
OR `b6` IN ('one', 'two', 'thr.ee')
OR `b7` IN (NULL)
OR `b8` IN (RAND() `col1` > `col2` )
OR `b9` IN (RAND(), [col1] > [col2] )
@@ -316,8 +322,8 @@ WHERE ("test"."a" LIKE \'1995-03-01\'
OR "b2" IN (\'1\', \'2\', \'3\' )
OR "b3" IN ( )
OR "b4" IN ( \'one\', \'two\', \'three\' )
OR "b5" IN ("col1" AS "one", "col2" AS "two", "col3" AS "three" )
OR "b6" IN (\'one\', \'two\', \'three\')
OR "b5" IN ("col1" AS "one", "col2" AS "two", "col3" AS "thr.ee" )
OR "b6" IN (\'one\', \'two\', \'thr.ee\')
OR "b7" IN (NULL)
OR "b8" IN (RAND() "col1" > "col2" )
OR "b9" IN (RAND(), [col1] > [col2] )
@@ -337,8 +343,8 @@ WHERE ([test].[a] LIKE #03/01/1995#
OR [b2] IN ('1', '2', '3' )
OR [b3] IN ( )
OR [b4] IN ( 'one', 'two', 'three' )
OR [b5] IN ([col1] AS [one], [col2] AS [two], [col3] AS [three] )
OR [b6] IN ('one', 'two', 'three')
OR [b5] IN ([col1] AS [one], [col2] AS [two], [col3] AS [thr.ee] )
OR [b6] IN ('one', 'two', 'thr.ee')
OR [b7] IN (NULL)
OR [b8] IN (RAND() [col1] > [col2] )
OR [b9] IN (RAND(), [col1] > [col2] )
@@ -358,8 +364,8 @@ WHERE ([test].[a] LIKE '1995-03-01'
OR [b2] IN ('1', '2', '3' )
OR [b3] IN ( )
OR [b4] IN ( 'one', 'two', 'three' )
OR [b5] IN ([col1] AS [one], [col2] AS [two], [col3] AS [three] )
OR [b6] IN ('one', 'two', 'three')
OR [b5] IN ([col1] AS [one], [col2] AS [two], [col3] AS [thr.ee] )
OR [b6] IN ('one', 'two', 'thr.ee')
OR [b7] IN (NULL)
OR [b8] IN (RAND() [col1] > [col2] )
OR [b9] IN (RAND(), [col1] > [col2] )
@@ -425,6 +431,7 @@ Assert::same(
Assert::same(
reformat([
'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',
'SELECT * FROM [test] WHERE [id] LIKE \'%d%t\' LIMIT 10',
]),
$conn->translate("SELECT * FROM [test] WHERE %n LIKE '%d%t' %lmt", 'id', 10)
@@ -515,7 +522,7 @@ Assert::same(
Assert::same(
reformat('INSERT INTO 0'),
$conn->translate('INSERT INTO %f', 'ahoj')
@$conn->translate('INSERT INTO %f', 'ahoj') // triggers warning in PHP 7.1
);
@@ -535,6 +542,12 @@ Assert::same(
);
Assert::same(
reformat('SELECT [a].[b] AS [c.d]'),
$conn->translate('SELECT %n AS %N', 'a.b', 'c.d')
);
setLocale(LC_ALL, 'czech');
Assert::same(

View File

@@ -1,5 +1,3 @@
/*!40102 SET storage_engine = InnoDB */;
DROP DATABASE IF EXISTS dibi_test;
CREATE DATABASE dibi_test;
USE dibi_test;

View File

@@ -0,0 +1,5 @@
IF OBJECT_ID('aaa', 'U') IS NOT NULL DROP TABLE aaa;
IF OBJECT_ID('aab', 'U') IS NOT NULL DROP TABLE aab;
CREATE TABLE aaa ( [id] int NOT NULL IDENTITY PRIMARY KEY )
CREATE TABLE aab ( [id] int NOT NULL IDENTITY PRIMARY KEY )

View File

@@ -8,6 +8,7 @@ CREATE TABLE products (
title varchar(50) NOT NULL,
PRIMARY KEY(product_id)
);
CREATE INDEX [title] ON [dbo].[products] ([title]);
SET IDENTITY_INSERT products ON;
INSERT INTO products (product_id, title) VALUES (1, 'Chair');

View File

@@ -17,11 +17,12 @@ try {
Tester\Environment::skip($e->getMessage());
}
Assert::same(3, count($meta->getTables()));
$names = $meta->getTableNames();
sort($names);
Assert::equal(['customers', 'orders', 'products'], $names);
if ($config['system'] !== 'sqlsrv') {
Assert::same(3, count($meta->getTables()));
$names = $meta->getTableNames();
sort($names);
Assert::equal(['customers', 'orders', 'products'], $names);
}
Assert::false($meta->hasTable('xxxx'));
@@ -48,7 +49,7 @@ Assert::same('title', $column->getName());
Assert::same('products', $column->getTable()->getName());
Assert::same('s', $column->getType());
Assert::type('string', $column->getNativeType());
Assert::same(100, $column->getSize());
Assert::same($config['system'] === 'sqlsrv' ? 50 : 100, $column->getSize());
Assert::false($column->isNullable());
Assert::false($column->isAutoIncrement());
//Assert::null($column->getDefault());

18
tests/php5-win.ini Normal file
View File

@@ -0,0 +1,18 @@
[PHP]
extension_dir = "./ext"
;extension=php_mssql.dll
extension=php_mysql.dll
extension=php_mysqli.dll
;extension=php_oci8.dll
;extension=php_oci8_11g.dll
;extension=php_pdo_firebird.dll
;extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
extension=php_pdo_odbc.dll
extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
extension=php_pgsql.dll
extension=php_sqlite3.dll
extension=php_sqlsrv_ts.dll
extension=php_pdo_sqlsrv_ts.dll

View File

@@ -1,10 +1,11 @@
[PHP]
extension_dir = "./ext"
extension=php_mysql.dll
;extension=php_mssql.dll
extension=php_mysqli.dll
;extension=php_oci8.dll
;extension=php_oci8_11g.dll
;extension=php_pdo_firebird.dll
;extension=php_pdo_mssql.dll
extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
extension=php_pdo_odbc.dll
@@ -12,4 +13,5 @@ extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
extension=php_pgsql.dll
extension=php_sqlite3.dll
;extension=php_sqlsrv_ts.dll
extension=php_sqlsrv_ts.dll
extension=php_odbc.dll