Skip to content

Commit

Permalink
Merge pull request #19 from chukShirley/odbc-support
Browse files Browse the repository at this point in the history
Support PDO ODBC connections
  • Loading branch information
chukShirley committed Mar 9, 2020
2 parents ef48978 + 187062e commit 962e248
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 3 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"doctrine/dbal": "^2.5"
},
"require-dev": {
"doctrine/orm": "dev-master",
"doctrine/orm": "^2.0.0",
"phpunit/phpunit": "^5.6"
},
"autoload": {
Expand Down
61 changes: 61 additions & 0 deletions src/Driver/OdbcDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace DoctrineDbalIbmi\Driver;

use Doctrine\DBAL\VersionAwarePlatformDriver;
use DoctrineDbalIbmi\Platform\DB2IBMiPlatform;
use DoctrineDbalIbmi\Schema\DB2IBMiSchemaManager;

class OdbcDriver extends AbstractDB2Driver implements VersionAwarePlatformDriver
{
/**
* {@inheritdoc}
*/
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{
$params['dsn'] = 'odbc:' . $params['dsn'];
$username = (!is_null($username)) ? $username : $params['username'];
$password = (!is_null($password)) ? $password : $params['password'];

return new OdbcIBMiConnection($params, $username, $password, $driverOptions);
}

/**
* {@inheritdoc}
*/
public function getName()
{
return 'odbc';
}

public function createDatabasePlatformForVersion($version)
{
return new DB2IBMiPlatform();
}

/**
* {@inheritdoc}
*/
public function getDatabase(\Doctrine\DBAL\Connection $conn)
{
$params = $conn->getParams();

return $params['dbname'];
}

/**
* {@inheritdoc}
*/
public function getDatabasePlatform()
{
return new DB2IBMiPlatform();
}

/**
* {@inheritdoc}
*/
public function getSchemaManager(\Doctrine\DBAL\Connection $conn)
{
return new DB2IBMiSchemaManager($conn);
}
}
93 changes: 93 additions & 0 deletions src/Driver/OdbcIBMiConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace DoctrineDbalIbmi\Driver;

use Doctrine\DBAL\Driver\IBMDB2\DB2Connection;
use Doctrine\DBAL\Driver\PDOConnection;

/**
* IBMi Db2 Connection.
* More documentation about iSeries schema at https://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/db2/rbafzcatsqlcolumns.htm
*
* @author Cassiano Vailati <c.vailati@esconsulting.it>
* @author James Titcumb <james@asgrim.com>
*/
class OdbcIBMiConnection extends PDOConnection
{
protected $driverOptions = array();

/**
* @param array $params
* @param string $username
* @param string $password
* @param array $driverOptions
*
* @throws \Doctrine\DBAL\Driver\IBMDB2\DB2Exception
*/
public function __construct($params, $username, $password, $driverOptions = array())
{
$this->driverOptions = $driverOptions;
$this->driverOptions[\PDO::ATTR_PERSISTENT] = false;
if (isset($params['persistent'])) {
$this->driverOptions[\PDO::ATTR_PERSISTENT] = $params['persistent'];
}
parent::__construct($params['dsn'], $username, $password, $this->driverOptions);
}

/**
* {@inheritdoc}
*/
public function lastInsertId($name = null)
{
$sql = 'SELECT IDENTITY_VAL_LOCAL() AS VAL FROM QSYS2'.$this->getSchemaSeparatorSymbol().'QSQPTABL';
$stmt = $this->prepare($sql);
$stmt->execute();

$res = $stmt->fetch();

return $res['VAL'];
}

/**
* Returns the appropriate schema separation symbol for i5 systems.
* Other systems can hardcode '.' but i5 may need '.' or '/' depending on the naming mode.
*
* @return string
*/
public function getSchemaSeparatorSymbol()
{
// if "i5 naming" is on, use '/' to separate schema and table. Otherwise use '.'
if (array_key_exists('i5_naming', $this->driverOptions) && $this->driverOptions['i5_naming']) {

// "i5 naming" mode requires a slash
return '/';

} else {
// SQL naming requires a dot
return '.';
}
}

/**
*
* Retrieves ibm_db2 native resource handle.
*
* Could be used if part of your application is not using DBAL.
*
* @return resource
*/
public function getWrappedResourceHandle()
{
$connProperty = new \ReflectionProperty(DB2Connection::class, '_conn');
$connProperty->setAccessible(true);
return $connProperty->getValue($this);
}

/**
* @return bool
*/
public function requiresQueryForServerVersion()
{
return true;
}
}
4 changes: 2 additions & 2 deletions test/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ class Bootstrap
public static function getEntityManager()
{
if (null === self::$entityManager) {
if (!extension_loaded('ibm_db2')) {
throw new \PHPUnit_Framework_SkippedTestError('DB2 connection is unavailable, skipping test');
if (!extension_loaded('ibm_db2') && !extension_loaded('pdo')) {
throw new \PHPUnit_Framework_SkippedTestError('Neither DB2 nor PDO connections are unavailable, skipping test');
}

$configuration = Setup::createAnnotationMetadataConfiguration([
Expand Down
10 changes: 10 additions & 0 deletions test/config/local.php.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

// For use with ibm_db2 extension
return [
'driverClass' => \DoctrineDbalIbmi\Driver\DB2Driver::class,
'host' => 'localhost',
Expand All @@ -13,3 +14,12 @@ return [
'i5_commit' => DB2_I5_TXN_NO_COMMIT,
],
];

// For use with odbc and pdo extension
return [
'driverClass' => \DoctrineDbalIbmi\Driver\OdbcDriver::class,
'persistent' => false,
'dsn' => "DSN=*LOCAL;",
'username' => 'CHANGEME',
'password' => 'METOO',
];
3 changes: 3 additions & 0 deletions test/unit/Driver/DB2IBMiConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class DB2IBMiConnectionTest extends \PHPUnit_Framework_TestCase
{
public function testCorrectConnectionClassIsUsed()
{
if (!extension_loaded('ibm_db2')) {
$this->markTestSkipped('ibm_db2 extension not loaded');
}
$em = Bootstrap::getEntityManager();

$connection = $em->getConnection()->getWrappedConnection();
Expand Down
25 changes: 25 additions & 0 deletions test/unit/Driver/OdbcIbmiConnectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace DoctrineDbalIbmiTest\Driver;

use DoctrineDbalIbmi\Driver\DB2IBMiConnection;
use DoctrineDbalIbmi\Driver\OdbcIBMiConnection;
use DoctrineDbalIbmiTest\Bootstrap;
use PHPUnit\Framework\TestCase;

final class OdbcIbmiConnectionTest extends TestCase
{
public function testCorrectConnectionClassIsUsed()
{
if (!extension_loaded('pdo')) {
$this->markTestSkipped('pdo extension not loaded');
}
$em = Bootstrap::getEntityManager();

$connection = $em->getConnection()->getWrappedConnection();

self::assertInstanceOf(OdbcIBMiConnection::class, $connection);
}
}
6 changes: 6 additions & 0 deletions test/unit/Platform/DB2IBMiPlatformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public function typeMappingProvider()
*/
public function testTypeMappings($dbType, $expectedMapping)
{
if (!extension_loaded('ibm_db2')) {
$this->markTestSkipped('ibm_db2 extension not loaded');
}
$em = Bootstrap::getEntityManager();
/** @var DB2IBMiPlatform $platform */
$platform = $em->getConnection()->getDatabasePlatform();
Expand Down Expand Up @@ -83,6 +86,9 @@ public function varcharTypeDeclarationProvider()
*/
public function testVarcharTypeDeclarationSQLSnippet($expectedSql, array $fieldDef)
{
if (!extension_loaded('ibm_db2')) {
$this->markTestSkipped('ibm_db2 extension not loaded');
}
$em = Bootstrap::getEntityManager();
/** @var DB2IBMiPlatform $platform */
$platform = $em->getConnection()->getDatabasePlatform();
Expand Down

0 comments on commit 962e248

Please sign in to comment.