Unverified Commit 9e68c3cc authored by Marco Pivetta's avatar Marco Pivetta Committed by GitHub

Merge pull request #2617 from photodude/patch-2

Testing of MSSQL on Windows with AppVeyor
parents 3bfaa821 cadd79c6
build: false
platform:
- x64
#matrix:
# fast_finish: true # kills the build at the first failure
clone_folder: C:\projects\dbal
clone_depth: 1
cache:
- C:\ProgramData\chocolatey\bin -> .appveyor.yml
- C:\ProgramData\chocolatey\lib -> .appveyor.yml
- c:\tools\php -> .appveyor.yml
- composer.phar
- '%LOCALAPPDATA%\Composer\files'
#- vendor
## Build matrix for lowest and highest possible targets
environment:
matrix:
- db: mssql
driver: sqlsrv
db_version: sql2008r2sp2
php: 7.1
- db: mssql
driver: sqlsrv
db_version: sql2012sp1
php: 7.1
- db: mssql
driver: sqlsrv
db_version: sql2017
php: 7.1
- db: mssql
driver: pdo_sqlsrv
db_version: sql2017
php: 7.1
init:
- SET PATH=C:\Program Files\OpenSSL;c:\tools\php;%PATH%
- SET COMPOSER_NO_INTERACTION=1
- SET ANSICON=121x90 (121x90)
## Install PHP and composer, and run the appropriate composer command
install:
- ps: |
# Check if installation is cached
if (!(Test-Path c:\tools\php)) {
appveyor-retry cinst --params '""/InstallDir:C:\tools\php""' --ignore-checksums -y php --version ((choco search php --exact --all-versions -r | select-string -pattern $env:php | sort { [version]($_ -split '\|' | select -last 1) } -Descending | Select-Object -first 1) -replace '[php|]','')
# install sqlite
appveyor-retry cinst -y sqlite
Get-ChildItem -Path c:\tools\php
cd c:\tools\php
# Set PHP environment items that are always needed
copy php.ini-production php.ini
Add-Content php.ini "`n date.timezone=UTC"
Add-Content php.ini "`n extension_dir=ext"
Add-Content php.ini "`n extension=php_openssl.dll"
Add-Content php.ini "`n extension=php_mbstring.dll"
Add-Content php.ini "`n extension=php_fileinfo.dll"
Add-Content php.ini "`n extension=php_pdo_sqlite.dll"
Add-Content php.ini "`n extension=php_sqlite3.dll"
# If needed get the MSSQL DLL's
if ($env:db -eq "mssql") {
$DLLVersion = "5.2.0rc1"
cd c:\tools\php\ext
$source = "https://windows.php.net/downloads/pecl/releases/sqlsrv/$($DLLVersion)/php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip"
$destination = "c:\tools\php\ext\php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip"
Invoke-WebRequest $source -OutFile $destination
7z x -y php_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip > $null
$source = "https://windows.php.net/downloads/pecl/releases/pdo_sqlsrv/$($DLLVersion)/php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip"
$destination = "c:\tools\php\ext\php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip"
Invoke-WebRequest $source -OutFile $destination
7z x -y php_pdo_sqlsrv-$($DLLVersion)-$($env:php)-nts-vc14-x64.zip > $null
Remove-Item c:\tools\php\* -include .zip
cd c:\tools\php
Add-Content php.ini "`nextension=php_sqlsrv.dll"
Add-Content php.ini "`nextension=php_pdo_sqlsrv.dll"
Add-Content php.ini "`n"
}
cd c:\projects\dbal
if (!(Test-Path c:\projects\dbal\composer.phar)) {
appveyor-retry appveyor DownloadFile https://getcomposer.org/composer.phar
}
}
# install composer dependencies
- appveyor-retry php composer.phar self-update
- appveyor-retry php composer.phar install --no-progress --profile
before_test:
# Selectively start the services
- ps: >-
if ($env:db -eq "mssql") {
$instanceName = $env:db_version.ToUpper()
Start-Service "MSSQL`$$instanceName"
}
test_script:
- cd C:\projects\dbal
- ps: >-
if ($env:db_version) {
vendor\bin\phpunit -c tests\appveyor\%db%.%db_version%.%driver%.appveyor.xml
}
else {
vendor\bin\phpunit -c tests\appveyor\%db%.%driver%.appveyor.xml
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
.gitattributes export-ignore .gitattributes export-ignore
.gitignore export-ignore .gitignore export-ignore
.gitmodules export-ignore .gitmodules export-ignore
.appveyor.yml export-ignore
.travis.yml export-ignore .travis.yml export-ignore
build.properties export-ignore build.properties export-ignore
build.xml export-ignore build.xml export-ignore
......
...@@ -42,6 +42,6 @@ ...@@ -42,6 +42,6 @@
} }
}, },
"archive": { "archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar"] "exclude": ["!vendor", "tests", "*phpunit.xml", ".appveyor.yml", ".travis.yml", "build.xml", "build.properties", "composer.phar"]
} }
} }
...@@ -136,11 +136,11 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection ...@@ -136,11 +136,11 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
if ($name !== null) { if ($name !== null) {
$stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?'); $stmt = $this->prepare('SELECT CONVERT(VARCHAR(MAX), current_value) FROM sys.sequences WHERE name = ?');
$stmt->execute([$name]); $stmt->execute([$name]);
} else {
return $stmt->fetchColumn(); $stmt = $this->query('SELECT @@IDENTITY');
} }
return $this->lastInsertId->getId(); return $stmt->fetchColumn();
} }
/** /**
......
...@@ -24,6 +24,7 @@ use Doctrine\DBAL\FetchMode; ...@@ -24,6 +24,7 @@ use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Driver\Statement;
use function func_get_args;
/** /**
* SQL Server Statement. * SQL Server Statement.
...@@ -348,19 +349,19 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -348,19 +349,19 @@ class SQLSrvStatement implements IteratorAggregate, Statement
switch ($fetchMode) { switch ($fetchMode) {
case FetchMode::CUSTOM_OBJECT: case FetchMode::CUSTOM_OBJECT:
while ($row = call_user_func_array([$this, 'fetch'], func_get_args())) { while (($row = $this->fetch(...func_get_args())) !== false) {
$rows[] = $row; $rows[] = $row;
} }
break; break;
case FetchMode::COLUMN: case FetchMode::COLUMN:
while ($row = $this->fetchColumn()) { while (($row = $this->fetchColumn()) !== false) {
$rows[] = $row; $rows[] = $row;
} }
break; break;
default: default:
while ($row = $this->fetch($fetchMode)) { while (($row = $this->fetch($fetchMode)) !== false) {
$rows[] = $row; $rows[] = $row;
} }
} }
......
...@@ -28,6 +28,8 @@ use Doctrine\DBAL\Schema\Index; ...@@ -28,6 +28,8 @@ use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Schema\TableDiff; use Doctrine\DBAL\Schema\TableDiff;
use Doctrine\DBAL\Types; use Doctrine\DBAL\Types;
use function implode;
use function sprintf;
/** /**
* The SQLServerPlatform provides the behavior, features and SQL dialect of the * The SQLServerPlatform provides the behavior, features and SQL dialect of the
...@@ -1207,19 +1209,29 @@ class SQLServerPlatform extends AbstractPlatform ...@@ -1207,19 +1209,29 @@ class SQLServerPlatform extends AbstractPlatform
*/ */
protected function doModifyLimitQuery($query, $limit, $offset = null) protected function doModifyLimitQuery($query, $limit, $offset = null)
{ {
if ($limit === null) { $where = [];
return $query;
if ($offset > 0) {
$where[] = sprintf('doctrine_rownum >= %d', $offset + 1);
} }
$start = $offset + 1; if ($limit !== null) {
$end = $offset + $limit; $where[] = sprintf('doctrine_rownum <= %d', $offset + $limit);
$top = sprintf('TOP %d', $offset + $limit);
} else {
$top = 'TOP 9223372036854775807';
}
if (empty($where)) {
return $query;
}
// We'll find a SELECT or SELECT distinct and prepend TOP n to it // We'll find a SELECT or SELECT distinct and prepend TOP n to it
// Even if the TOP n is very large, the use of a CTE will // Even if the TOP n is very large, the use of a CTE will
// allow the SQL Server query planner to optimize it so it doesn't // allow the SQL Server query planner to optimize it so it doesn't
// actually scan the entire range covered by the TOP clause. // actually scan the entire range covered by the TOP clause.
$selectPattern = '/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/im'; $selectPattern = '/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/im';
$replacePattern = sprintf('$1%s $2', "TOP $end"); $replacePattern = sprintf('$1%s $2', $top);
$query = preg_replace($selectPattern, $replacePattern, $query); $query = preg_replace($selectPattern, $replacePattern, $query);
if (stristr($query, "ORDER BY")) { if (stristr($query, "ORDER BY")) {
...@@ -1234,10 +1246,9 @@ class SQLServerPlatform extends AbstractPlatform ...@@ -1234,10 +1246,9 @@ class SQLServerPlatform extends AbstractPlatform
. "SELECT * FROM (" . "SELECT * FROM ("
. "SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte" . "SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte"
. ") AS doctrine_tbl " . ") AS doctrine_tbl "
. "WHERE doctrine_rownum BETWEEN %d AND %d ORDER BY doctrine_rownum ASC", . 'WHERE %s ORDER BY doctrine_rownum ASC',
$query, $query,
$start, implode(' AND ', $where)
$end
); );
} }
......
...@@ -4,9 +4,10 @@ namespace Doctrine\Tests\DBAL\Driver\Mysqli; ...@@ -4,9 +4,10 @@ namespace Doctrine\Tests\DBAL\Driver\Mysqli;
use Doctrine\DBAL\Driver\Mysqli\MysqliConnection; use Doctrine\DBAL\Driver\Mysqli\MysqliConnection;
use Doctrine\DBAL\Driver\Mysqli\MysqliException; use Doctrine\DBAL\Driver\Mysqli\MysqliException;
use Doctrine\Tests\DbalTestCase; use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\Tests\DbalFunctionalTestCase;
class MysqliConnectionTest extends DbalTestCase class MysqliConnectionTest extends DbalFunctionalTestCase
{ {
/** /**
* The mysqli driver connection mock under test. * The mysqli driver connection mock under test.
...@@ -23,6 +24,10 @@ class MysqliConnectionTest extends DbalTestCase ...@@ -23,6 +24,10 @@ class MysqliConnectionTest extends DbalTestCase
parent::setUp(); parent::setUp();
if (! $this->_conn->getDatabasePlatform() instanceof MySqlPlatform) {
$this->markTestSkipped('MySQL only test.');
}
$this->connectionMock = $this->getMockBuilder(MysqliConnection::class) $this->connectionMock = $this->getMockBuilder(MysqliConnection::class)
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMockForAbstractClass(); ->getMockForAbstractClass();
...@@ -49,6 +54,4 @@ class MysqliConnectionTest extends DbalTestCase ...@@ -49,6 +54,4 @@ class MysqliConnectionTest extends DbalTestCase
restore_error_handler(); restore_error_handler();
restore_error_handler(); restore_error_handler();
} }
} }
...@@ -49,12 +49,22 @@ class SQLServerPlatformTest extends AbstractSQLServerPlatformTestCase ...@@ -49,12 +49,22 @@ class SQLServerPlatformTest extends AbstractSQLServerPlatformTestCase
public function getModifyLimitQueries() public function getModifyLimitQueries()
{ {
return array( return [
// Test re-ordered query with correctly-scrubbed ORDER BY clause // Test re-ordered query with correctly-scrubbed ORDER BY clause
array('SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_ ORDER BY c0_.title ASC) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, null, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum BETWEEN 1 AND 30 ORDER BY doctrine_rownum ASC'), [
'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_ ORDER BY c0_.title ASC) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC',
30,
null,
'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC',
],
// Test re-ordered query with no scrubbed ORDER BY clause // Test re-ordered query with no scrubbed ORDER BY clause
array('SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', 30, null, 'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum BETWEEN 1 AND 30 ORDER BY doctrine_rownum ASC'), [
); 'SELECT id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC',
30,
null,
'WITH dctrn_cte AS (SELECT TOP 30 id_0, MIN(sclr_2) AS dctrn_minrownum FROM (SELECT c0_.id AS id_0, c0_.title AS title_1, ROW_NUMBER() OVER(ORDER BY c0_.title ASC) AS sclr_2 FROM TestTable c0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC) SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS doctrine_rownum FROM dctrn_cte) AS doctrine_tbl WHERE doctrine_rownum <= 30 ORDER BY doctrine_rownum ASC',
],
];
} }
} }
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="../../vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="sqlsrv"/>
<var name="db_host" value="(local)\SQL2008R2SP2" />
<var name="db_username" value="sa" />
<var name="db_password" value="Password12!" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="1433" />
<var name="tmpdb_type" value="sqlsrv"/>
<var name="tmpdb_host" value="(local)\SQL2008R2SP2" />
<var name="tmpdb_username" value="sa" />
<var name="tmpdb_password" value="Password12!" />
<var name="tmpdb_port" value="1433" />
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="../../vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="sqlsrv"/>
<var name="db_host" value="(local)\SQL2012SP1" />
<var name="db_username" value="sa" />
<var name="db_password" value="Password12!" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="1433" />
<var name="tmpdb_type" value="sqlsrv"/>
<var name="tmpdb_host" value="(local)\SQL2012SP1" />
<var name="tmpdb_username" value="sa" />
<var name="tmpdb_password" value="Password12!" />
<var name="tmpdb_port" value="1433" />
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="../../vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="pdo_sqlsrv"/>
<var name="db_host" value="(local)\SQL2017" />
<var name="db_username" value="sa" />
<var name="db_password" value="Password12!" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="1433"/>
<var name="tmpdb_type" value="pdo_sqlsrv"/>
<var name="tmpdb_host" value="(local)\SQL2017" />
<var name="tmpdb_username" value="sa" />
<var name="tmpdb_password" value="Password12!" />
<var name="tmpdb_port" value="1433"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.8/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="../../vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="sqlsrv"/>
<var name="db_host" value="(local)\SQL2017" />
<var name="db_username" value="sa" />
<var name="db_password" value="Password12!" />
<var name="db_name" value="doctrine_tests" />
<var name="db_port" value="1433" />
<var name="tmpdb_type" value="sqlsrv"/>
<var name="tmpdb_host" value="(local)\SQL2017" />
<var name="tmpdb_username" value="sa" />
<var name="tmpdb_password" value="Password12!" />
<var name="tmpdb_port" value="1433" />
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment