nextras / dbal

Database Abstraction Layer – concise secure API to construct queries & fetch data
https://nextras.org/dbal
MIT License
79 stars 28 forks source link

Cannot reuse connection for different database #13

Closed Mikulas closed 9 years ago

Mikulas commented 9 years ago

(moved from https://github.com/nextras/orm/issues/96)

Postgres can't change databases without reconnecting.

In our test suite, we'd like to create separate a test database with automatically generated name for each test. Overriding container is not an option because at the time test run container is already compiled.

public function runTest($name, array $args = array())
{
        /* MARK */ 

    // close connection created by container, if any
    $this->connection->getDriver()->disconnect();

    $parameters = $this->container->getParameters();

        // .. creating test database

    $config = $parameters['dbal'];
    $config['dbname'] = $testDbName;

    $this->connection->getDriver()->connect($config);
    parent::runTest($name, $args);
}

This does not work as expected, because connection has $this->connected === FALSE and will call Connection::connect() which calls driver connect with original config.

Proposed solutions:

Partial hack: calling $this->connection->connect(); at /* MARK */ is a workaround, but onConnect event is not called (which is correct but undesirable in this case).

Note: I'd generally create new instance of connection, but since this instance is already autowired and injected to multiple other instances, it's not plausible.

hrach commented 9 years ago

Well, give a look at nextras orm test suite. There is usecase with multiple containers. Probably, I would prefere the first option - add config setter for Connection.

Mikulas commented 9 years ago

Current solution is not correct, SqlProcessor and possibly other classes have pointer to the old driver, failing on

E_WARNING: pg_escape_literal() expects parameter 1 to be resource, null given

in Drivers/Pgsql/PgsqlDriver.php(207) in Drivers/Pgsql/PgsqlDriver.php(207) pg_escape_literal() in dbal/src/SqlProcessor.php(118) Nextras\Dbal\Drivers\Pgsql\PgsqlDriver->convertToSql() in dbal/src/SqlProcessor.php(81) Nextras\Dbal\SqlProcessor->processModifier() in [internal function]Nextras\Dbal\SqlProcessor->Nextras\Dbal{closure}()

Proposed solution:

 class Connection
@@ -105,6 +106,7 @@ public function reconnectWithConfig(array $config)
                $this->disconnect();
                $this->config = $this->processConfig($config);
                $this->driver = $this->createDriver($this->config);
+               $this->sqlPreprocessor = new SqlProcessor($this->driver);
                $this->connect();
        }