Browse Source

Remove the 'persistent' config option for Sqlserver connections

- The PDO::ATTR_PERSISTENT connection configuration option is not allowed
  by the SQL Server PHP driver.  In newer versions of the driver an
  exception is thrown if that option is set.  In older versions of the
  driver it triggered a heap corruption bug which usually caused
  intermittent crashes.
Mike Fellows 8 years ago
parent
commit
43959d9926
2 changed files with 80 additions and 5 deletions
  1. 12 3
      src/Database/Driver/Sqlserver.php
  2. 68 2
      tests/TestCase/Database/Driver/SqlserverTest.php

+ 12 - 3
src/Database/Driver/Sqlserver.php

@@ -35,7 +35,6 @@ class Sqlserver extends Driver
      * @var array
      */
     protected $_baseConfig = [
-        'persistent' => false,
         'host' => 'localhost\SQLEXPRESS',
         'username' => '',
         'password' => '',
@@ -54,8 +53,14 @@ class Sqlserver extends Driver
     ];
 
     /**
-     * Establishes a connection to the database server
+     * Establishes a connection to the database server.
      *
+     * Please note that the PDO::ATTR_PERSISTENT attribute is not supported by
+     * the SQL Server PHP PDO drivers.  As a result you cannot use the
+     * persistent config option when connecting to a SQL Server  (for more
+     * information see: https://github.com/Microsoft/msphpsql/issues/65).
+     *
+     * @throws \InvalidArgumentException if an unsupported setting is in the driver config
      * @return bool true on success
      */
     public function connect()
@@ -64,8 +69,12 @@ class Sqlserver extends Driver
             return true;
         }
         $config = $this->_config;
+
+        if (isset($config['persistent']) && $config['persistent']) {
+            throw new \InvalidArgumentException('Config setting "persistent" cannot be set to true, as the Sqlserver PDO driver does not support PDO::ATTR_PERSISTENT');
+        }
+
         $config['flags'] += [
-            PDO::ATTR_PERSISTENT => $config['persistent'],
             PDO::ATTR_EMULATE_PREPARES => false,
             PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
         ];

+ 68 - 2
tests/TestCase/Database/Driver/SqlserverTest.php

@@ -103,7 +103,6 @@ class SqlserverTest extends TestCase
     {
         $this->skipIf($this->missingExtension, 'pdo_sqlsrv is not installed.');
         $config = [
-            'persistent' => false,
             'host' => 'foo',
             'username' => 'Administrator',
             'password' => 'blablabla',
@@ -121,7 +120,6 @@ class SqlserverTest extends TestCase
 
         $expected = $config;
         $expected['flags'] += [
-            PDO::ATTR_PERSISTENT => false,
             PDO::ATTR_EMULATE_PREPARES => false,
             PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
             PDO::SQLSRV_ATTR_ENCODING => 'a-language'
@@ -160,6 +158,74 @@ class SqlserverTest extends TestCase
     }
 
     /**
+     * Test connecting to Sqlserver with persistent set to false
+     *
+     * @return void
+     */
+    public function testConnectionPersistentFalse()
+    {
+        $this->skipIf($this->missingExtension, 'pdo_sqlsrv is not installed.');
+        $config = [
+            'persistent' => false,
+            'host' => 'foo',
+            'username' => 'Administrator',
+            'password' => 'blablabla',
+            'database' => 'bar',
+            'encoding' => 'a-language',
+        ];
+        $driver = $this->getMockBuilder('Cake\Database\Driver\Sqlserver')
+            ->setMethods(['_connect', 'connection'])
+            ->setConstructorArgs([$config])
+            ->getMock();
+        $dsn = 'sqlsrv:Server=foo;Database=bar;MultipleActiveResultSets=false';
+
+        $expected = $config;
+        $expected['flags'] = [
+            PDO::ATTR_EMULATE_PREPARES => false,
+            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+            PDO::SQLSRV_ATTR_ENCODING => 'a-language'
+        ];
+        $expected['attributes'] = [];
+        $expected['settings'] = [];
+        $expected['init'] = [];
+        $expected['app'] = null;
+        $expected['connectionPooling'] = null;
+        $expected['failoverPartner'] = null;
+        $expected['loginTimeout'] = null;
+        $expected['multiSubnetFailover'] = null;
+
+        $driver->expects($this->once())->method('_connect')
+            ->with($dsn, $expected);
+
+        $driver->connect();
+    }
+
+    /**
+     * Test if attempting to connect with the driver throws an exception when
+     * using an invalid config setting.
+     *
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage Config setting "persistent" cannot be set to true, as the Sqlserver PDO driver does not support PDO::ATTR_PERSISTENT
+     * @return void
+     */
+    public function testConnectionPersistentTrueException()
+    {
+        $this->skipIf($this->missingExtension, 'pdo_sqlsrv is not installed.');
+        $config = [
+            'persistent' => true,
+            'host' => 'foo',
+            'username' => 'Administrator',
+            'password' => 'blablabla',
+            'database' => 'bar',
+        ];
+        $driver = $this->getMockBuilder('Cake\Database\Driver\Sqlserver')
+            ->setMethods(['_connect', 'connection'])
+            ->setConstructorArgs([$config])
+            ->getMock();
+        $driver->connect();
+    }
+
+    /**
      * Test select with limit only and SQLServer2012+
      *
      * @return void