Unverified Commit d48ea9c2 authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #3133 from Majkl578/travis-db2

Enable testing with IBM DB2 on Travis 
parents 75d6c444 e2e0de25
...@@ -21,7 +21,7 @@ before_commands: ...@@ -21,7 +21,7 @@ before_commands:
tools: tools:
external_code_coverage: external_code_coverage:
timeout: 3600 timeout: 3600
runs: 21 # 17x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 1x ContinuousPHP runs: 22 # 18x Travis (jobs with COVERAGE=yes) + 3x AppVeyor (jobs with coverage=yes) + 1x ContinuousPHP
filter: filter:
excluded_paths: excluded_paths:
......
...@@ -356,6 +356,24 @@ jobs: ...@@ -356,6 +356,24 @@ jobs:
- bash ./tests/travis/install-mssql-$DB.sh - bash ./tests/travis/install-mssql-$DB.sh
- bash ./tests/travis/install-mssql.sh - bash ./tests/travis/install-mssql.sh
- stage: Test
env: DB=ibm_db2 COVERAGE=yes
sudo: required
services:
- docker
before_script:
- bash ./tests/travis/install-db2.sh
- bash ./tests/travis/install-db2-$DB.sh
- stage: Test
php: 7.2
env: DB=ibm_db2
sudo: required
services:
- docker
before_script:
- bash ./tests/travis/install-db2.sh
- bash ./tests/travis/install-db2-$DB.sh
- stage: Test - stage: Test
php: 7.1 php: 7.1
env: DB=sqlite DEPENDENCIES=low env: DB=sqlite DEPENDENCIES=low
......
...@@ -289,17 +289,17 @@ class DB2Statement implements \IteratorAggregate, Statement ...@@ -289,17 +289,17 @@ class DB2Statement 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;
} }
} }
......
...@@ -299,7 +299,11 @@ abstract class AbstractPlatform ...@@ -299,7 +299,11 @@ abstract class AbstractPlatform
$fixed = $field['fixed'] ?? false; $fixed = $field['fixed'] ?? false;
if ($field['length'] > $this->getVarcharMaxLength()) { $maxLength = $fixed
? $this->getCharMaxLength()
: $this->getVarcharMaxLength();
if ($field['length'] > $maxLength) {
return $this->getClobTypeDeclarationSQL($field); return $this->getClobTypeDeclarationSQL($field);
} }
...@@ -594,6 +598,14 @@ abstract class AbstractPlatform ...@@ -594,6 +598,14 @@ abstract class AbstractPlatform
return "\n"; return "\n";
} }
/**
* Gets the maximum length of a char field.
*/
public function getCharMaxLength() : int
{
return $this->getVarcharMaxLength();
}
/** /**
* Gets the maximum length of a varchar field. * Gets the maximum length of a varchar field.
* *
......
...@@ -39,6 +39,14 @@ use function strtoupper; ...@@ -39,6 +39,14 @@ use function strtoupper;
class DB2Platform extends AbstractPlatform class DB2Platform extends AbstractPlatform
{ {
/**
* {@inheritdoc}
*/
public function getCharMaxLength() : int
{
return 254;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -55,6 +63,19 @@ class DB2Platform extends AbstractPlatform ...@@ -55,6 +63,19 @@ class DB2Platform extends AbstractPlatform
return 1; return 1;
} }
/**
* {@inheritDoc}
*/
public function getVarcharTypeDeclarationSQL(array $field)
{
// for IBM DB2, the CHAR max length is less than VARCHAR default length
if (! isset($field['length']) && ! empty($field['fixed'])) {
$field['length'] = $this->getCharMaxLength();
}
return parent::getVarcharTypeDeclarationSQL($field);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
...@@ -107,7 +128,7 @@ class DB2Platform extends AbstractPlatform ...@@ -107,7 +128,7 @@ class DB2Platform extends AbstractPlatform
*/ */
protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed) protected function getVarcharTypeDeclarationSQLSnippet($length, $fixed)
{ {
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(254)')
: ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)'); : ($length ? 'VARCHAR(' . $length . ')' : 'VARCHAR(255)');
} }
...@@ -116,7 +137,7 @@ class DB2Platform extends AbstractPlatform ...@@ -116,7 +137,7 @@ class DB2Platform extends AbstractPlatform
*/ */
protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed) protected function getBinaryTypeDeclarationSQLSnippet($length, $fixed)
{ {
return $fixed ? 'BINARY(' . ($length ?: 255) . ')' : 'VARBINARY(' . ($length ?: 255) . ')'; return $this->getVarcharTypeDeclarationSQLSnippet($length, $fixed) . ' FOR BIT DATA';
} }
/** /**
......
...@@ -26,7 +26,6 @@ class DateIntervalType extends Type ...@@ -26,7 +26,6 @@ class DateIntervalType extends Type
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{ {
$fieldDeclaration['length'] = 255; $fieldDeclaration['length'] = 255;
$fieldDeclaration['fixed'] = true;
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration); return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
} }
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
namespace Doctrine\Tests\DBAL\Functional; namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSrvDriver;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use const CASE_LOWER; use const CASE_LOWER;
use function array_change_key_case; use function array_change_key_case;
...@@ -17,25 +19,19 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -17,25 +19,19 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase
{ {
parent::setUp(); parent::setUp();
if ($this->_conn->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlsrv\Driver) { if ($this->_conn->getDriver() instanceof PDOSQLSrvDriver) {
$this->markTestSkipped('This test does not work on pdo_sqlsrv driver due to a bug. See: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/5a755bdd-41e9-45cb-9166-c9da4475bb94/how-to-set-null-for-varbinarymax-using-bindvalue-using-pdosqlsrv?forum=sqldriverforphp'); $this->markTestSkipped('This test does not work on pdo_sqlsrv driver due to a bug. See: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/5a755bdd-41e9-45cb-9166-c9da4475bb94/how-to-set-null-for-varbinarymax-using-bindvalue-using-pdosqlsrv?forum=sqldriverforphp');
} }
try { /* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */
/* @var $sm \Doctrine\DBAL\Schema\AbstractSchemaManager */ $table = new Table('blob_table');
$table = new \Doctrine\DBAL\Schema\Table("blob_table"); $table->addColumn('id', 'integer');
$table->addColumn('id', 'integer'); $table->addColumn('clobfield', 'text');
$table->addColumn('clobfield', 'text'); $table->addColumn('blobfield', 'blob');
$table->addColumn('blobfield', 'blob'); $table->setPrimaryKey(['id']);
$table->addColumn('binaryfield', 'binary', array('length' => 50));
$table->setPrimaryKey(array('id'));
$sm = $this->_conn->getSchemaManager(); $sm = $this->_conn->getSchemaManager();
$sm->createTable($table); $sm->dropAndCreateTable($table);
} catch(\Exception $e) {
}
$this->_conn->exec($this->_conn->getDatabasePlatform()->getTruncateTableSQL('blob_table'));
} }
public function testInsert() public function testInsert()
...@@ -44,12 +40,10 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -44,12 +40,10 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase
'id' => 1, 'id' => 1,
'clobfield' => 'test', 'clobfield' => 'test',
'blobfield' => 'test', 'blobfield' => 'test',
'binaryfield' => 'test',
], [ ], [
ParameterType::INTEGER, ParameterType::INTEGER,
ParameterType::STRING, ParameterType::STRING,
ParameterType::LARGE_OBJECT, ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT,
]); ]);
self::assertEquals(1, $ret); self::assertEquals(1, $ret);
...@@ -61,12 +55,10 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -61,12 +55,10 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase
'id' => 1, 'id' => 1,
'clobfield' => 'test', 'clobfield' => 'test',
'blobfield' => 'test', 'blobfield' => 'test',
'binaryfield' => 'test',
], [ ], [
ParameterType::INTEGER, ParameterType::INTEGER,
ParameterType::STRING, ParameterType::STRING,
ParameterType::LARGE_OBJECT, ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT,
]); ]);
$this->assertBlobContains('test'); $this->assertBlobContains('test');
...@@ -78,38 +70,20 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -78,38 +70,20 @@ class BlobTest extends \Doctrine\Tests\DbalFunctionalTestCase
'id' => 1, 'id' => 1,
'clobfield' => 'test', 'clobfield' => 'test',
'blobfield' => 'test', 'blobfield' => 'test',
'binaryfield' => 'test',
], [ ], [
ParameterType::INTEGER, ParameterType::INTEGER,
ParameterType::STRING, ParameterType::STRING,
ParameterType::LARGE_OBJECT, ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT,
]); ]);
$this->_conn->update('blob_table', [ $this->_conn->update('blob_table', [
'blobfield' => 'test2', 'blobfield' => 'test2',
'binaryfield' => 'test2',
], ['id' => 1], [ ], ['id' => 1], [
ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT, ParameterType::LARGE_OBJECT,
ParameterType::INTEGER, ParameterType::INTEGER,
]); ]);
$this->assertBlobContains('test2'); $this->assertBlobContains('test2');
$this->assertBinaryContains('test2');
}
private function assertBinaryContains($text)
{
$rows = $this->_conn->fetchAll('SELECT * FROM blob_table');
self::assertCount(1, $rows);
$row = array_change_key_case($rows[0], CASE_LOWER);
$blobValue = Type::getType('binary')->convertToPHPValue($row['binaryfield'], $this->_conn->getDatabasePlatform());
self::assertInternalType('resource', $blobValue);
self::assertEquals($text, stream_get_contents($blobValue));
} }
private function assertBlobContains($text) private function assertBlobContains($text)
......
...@@ -15,8 +15,8 @@ class DateExpressionTest extends DbalFunctionalTestCase ...@@ -15,8 +15,8 @@ class DateExpressionTest extends DbalFunctionalTestCase
public function testDifference(string $date1, string $date2, int $expected) : void public function testDifference(string $date1, string $date2, int $expected) : void
{ {
$table = new Table('date_expr_test'); $table = new Table('date_expr_test');
$table->addColumn('date1', 'date'); $table->addColumn('date1', 'datetime');
$table->addColumn('date2', 'date'); $table->addColumn('date2', 'datetime');
$this->_conn->getSchemaManager()->dropAndCreateTable($table); $this->_conn->getSchemaManager()->dropAndCreateTable($table);
$this->_conn->insert('date_expr_test', [ $this->_conn->insert('date_expr_test', [
'date1' => $date1, 'date1' => $date1,
......
...@@ -25,4 +25,9 @@ class Db2SchemaManagerTest extends SchemaManagerFunctionalTestCase ...@@ -25,4 +25,9 @@ class Db2SchemaManagerTest extends SchemaManagerFunctionalTestCase
self::assertNull($columns['bool']->getComment()); self::assertNull($columns['bool']->getComment());
self::assertSame("That's a comment", $columns['bool_commented']->getComment()); self::assertSame("That's a comment", $columns['bool_commented']->getComment());
} }
public function testListTableWithBinary()
{
self::markTestSkipped('Binary data type is currently not supported on DB2 LUW');
}
} }
<?php
declare(strict_types=1);
namespace Doctrine\Tests\DBAL\Functional\Types;
use Doctrine\DBAL\Driver\IBMDB2\DB2Driver;
use Doctrine\DBAL\Driver\OCI8\Driver as OCI8Driver;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Schema\Table;
use Doctrine\Tests\DbalFunctionalTestCase;
use function is_resource;
use function random_bytes;
use function str_replace;
use function stream_get_contents;
class BinaryTest extends DbalFunctionalTestCase
{
protected function setUp()
{
parent::setUp();
/** @see https://github.com/doctrine/dbal/issues/2787 */
if ($this->_conn->getDriver() instanceof OCI8Driver) {
$this->markTestSkipped('Filtering by binary fields is currently not supported on Oracle');
}
$table = new Table('binary_table');
$table->addColumn('id', 'binary', [
'length' => 16,
'fixed' => true,
]);
$table->addColumn('val', 'binary', ['length' => 64]);
$table->setPrimaryKey(['id']);
$sm = $this->_conn->getSchemaManager();
$sm->dropAndCreateTable($table);
}
public function testInsertAndSelect()
{
$id1 = random_bytes(16);
$id2 = random_bytes(16);
$value1 = random_bytes(64);
$value2 = random_bytes(64);
/** @see https://bugs.php.net/bug.php?id=76322 */
if ($this->_conn->getDriver() instanceof DB2Driver) {
$value1 = str_replace("\x00", "\xFF", $value1);
$value2 = str_replace("\x00", "\xFF", $value2);
}
$this->insert($id1, $value1);
$this->insert($id2, $value2);
$this->assertSame($value1, $this->select($id1));
$this->assertSame($value2, $this->select($id2));
}
private function insert(string $id, string $value) : void
{
$result = $this->_conn->insert('binary_table', [
'id' => $id,
'val' => $value,
], [
ParameterType::LARGE_OBJECT,
ParameterType::LARGE_OBJECT,
]);
self::assertSame(1, $result);
}
private function select(string $id)
{
$value = $this->_conn->fetchColumn(
'SELECT val FROM binary_table WHERE id = ?',
[$id],
0,
[ParameterType::LARGE_OBJECT]
);
// Currently, `BinaryType` mistakenly converts string values fetched from the DB to a stream.
// It should be the opposite. Streams should be used to represent large objects, not binary
// strings. The confusion comes from the PostgreSQL's type system where binary strings and
// large objects are represented by the same BYTEA type
if (is_resource($value)) {
$value = stream_get_contents($value);
}
return $value;
}
}
...@@ -216,7 +216,7 @@ class DB2PlatformTest extends AbstractPlatformTestCase ...@@ -216,7 +216,7 @@ class DB2PlatformTest extends AbstractPlatformTestCase
self::assertEquals('VARCHAR(255)', $this->_platform->getVarcharTypeDeclarationSQL(array())); self::assertEquals('VARCHAR(255)', $this->_platform->getVarcharTypeDeclarationSQL(array()));
self::assertEquals('VARCHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 10))); self::assertEquals('VARCHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL(array('length' => 10)));
self::assertEquals('CHAR(255)', $this->_platform->getVarcharTypeDeclarationSQL(array('fixed' => true))); self::assertEquals('CHAR(254)', $this->_platform->getVarcharTypeDeclarationSQL(['fixed' => true]));
self::assertEquals('CHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL($fullColumnDef)); self::assertEquals('CHAR(10)', $this->_platform->getVarcharTypeDeclarationSQL($fullColumnDef));
self::assertEquals('SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array())); self::assertEquals('SMALLINT', $this->_platform->getSmallIntTypeDeclarationSQL(array()));
...@@ -419,15 +419,14 @@ class DB2PlatformTest extends AbstractPlatformTestCase ...@@ -419,15 +419,14 @@ class DB2PlatformTest extends AbstractPlatformTestCase
public function testReturnsBinaryTypeDeclarationSQL() public function testReturnsBinaryTypeDeclarationSQL()
{ {
self::assertSame('VARBINARY(1)', $this->_platform->getBinaryTypeDeclarationSQL(array())); self::assertSame('VARCHAR(1) FOR BIT DATA', $this->_platform->getBinaryTypeDeclarationSQL([]));
self::assertSame('VARBINARY(255)', $this->_platform->getBinaryTypeDeclarationSQL(array('length' => 0))); self::assertSame('VARCHAR(255) FOR BIT DATA', $this->_platform->getBinaryTypeDeclarationSQL(['length' => 0]));
self::assertSame('VARBINARY(32704)', $this->_platform->getBinaryTypeDeclarationSQL(array('length' => 32704))); self::assertSame('VARCHAR(32704) FOR BIT DATA', $this->_platform->getBinaryTypeDeclarationSQL(['length' => 32704]));
self::assertSame('BLOB(1M)', $this->_platform->getBinaryTypeDeclarationSQL(array('length' => 32705))); self::assertSame('BLOB(1M)', $this->_platform->getBinaryTypeDeclarationSQL(['length' => 32705]));
self::assertSame('BINARY(1)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true))); self::assertSame('CHAR(1) FOR BIT DATA', $this->_platform->getBinaryTypeDeclarationSQL(['fixed' => true]));
self::assertSame('BINARY(255)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 0))); self::assertSame('CHAR(254) FOR BIT DATA', $this->_platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 0]));
self::assertSame('BINARY(32704)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32704))); self::assertSame('BLOB(1M)', $this->_platform->getBinaryTypeDeclarationSQL(['fixed' => true, 'length' => 32705]));
self::assertSame('BLOB(1M)', $this->_platform->getBinaryTypeDeclarationSQL(array('fixed' => true, 'length' => 32705)));
} }
/** /**
......
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_type" value="ibm_db2"/>
<var name="db_host" value="127.0.0.1"/>
<var name="db_username" value="db2inst1"/>
<var name="db_password" value="Doctrine2018"/>
<var name="db_name" value="HOSTNAME=127.0.0.1;UID=db2inst1;PWD=Doctrine2018;DATABASE=doctrine"/>
<var name="db_port" value="50000"/>
<var name="tmpdb_type" value="ibm_db2"/>
<var name="tmpdb_host" value="127.0.0.1"/>
<var name="tmpdb_username" value="db2inst1"/>
<var name="tmpdb_password" value="Doctrine2018"/>
<var name="tmpdb_name" value="HOSTNAME=127.0.0.1;UID=db2inst1;PWD=Doctrine2018;DATABASE=doctrine"/>
<var name="tmpdb_port" value="50000"/>
</php>
<testsuites>
<testsuite name="Doctrine DBAL Test Suite">
<directory>../Doctrine/Tests/DBAL</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">../../lib/Doctrine</directory>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
<groups>
<exclude>
<group>performance</group>
<group>locking_functional</group>
</exclude>
</groups>
</phpunit>
#!/usr/bin/env bash
set -ex
echo "Installing extension"
(
sudo apt install ksh
cd /tmp
wget http://cdn1.netmake.com.br/download/Conexao/DB2/Linux/x64_v10.5fp8_linuxx64_dsdriver.tar.gz
tar xf x64_v10.5fp8_linuxx64_dsdriver.tar.gz
ksh dsdriver/installDSDriver
pecl download ibm_db2
tar xf ibm_db2-*
rm ibm_db2-*.tgz
cd ibm_db2-*
phpize
./configure --with-IBM_DB2=/tmp/dsdriver
make -j `nproc`
make install
echo -e 'extension=ibm_db2.so\nibm_db2.instance_name=db2inst1' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/ibm_db2.ini
)
#!/usr/bin/env bash
set -ex
echo Setting up IBM DB2
sudo docker pull ibmcom/db2express-c:10.5.0.5-3.10.0
sudo docker run \
-d \
-p 50000:50000 \
-e DB2INST1_PASSWORD=Doctrine2018 \
-e LICENSE=accept \
--name db2 \
ibmcom/db2express-c:10.5.0.5-3.10.0 \
db2start
sleep 15
sudo docker exec db2 su - db2inst1 -c \
'db2 CREATE DB doctrine && db2 CONNECT TO doctrine && db2 CREATE USER TEMPORARY TABLESPACE doctrine_tbsp PAGESIZE 4 K'
echo DB2 started
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