Answer a question

I'm trying to connect to PostgreSQL using Unix socket. It's I think only one way to connect to database which is on host, but the application is in Docker (I follow the principle to not containerize not replicated database). I'm using Symfony 4 with latest Doctrine.

I made a test on raw PHP with PDO, and it works. I don't have idea how to enforce Doctrine to use unix socket.

<?php
$dbh = new PDO('pgsql:host=/var/run/postgresql;user=xxxx;dbname=zzzz;password=yyyy');
$dbh->setAttribute(PDO::ERRMODE_EXCEPTION, true);
var_dump($dbh->errorInfo());

$stmt = $dbh->query('SELECT 1 as dupa;');
$stmt->execute();

var_dump($stmt->fetchAll());

And the result of it is as expected:

www-data@ef0f2269b69a:~/html$ php o.php 
array(3) {
  [0]=>
  string(5) "00000"
  [1]=>
  NULL
  [2]=>
  NULL
}
array(1) {
  [0]=>
  array(2) {
    ["dupa"]=>
    int(1)
    [0]=>
    int(1)
  }
}

The problem is whatever I configure in Doctrine I get this:

In PDOConnection.php line 27:
                                                                        
  [PDOException (7)]                                                    
  SQLSTATE[08006] [7] could not connect to server: Connection refused   
        Is the server running on host "localhost" (127.0.0.1) and accepting  
        TCP/IP connections on port 5432?                                     
  could not connect to server: Cannot assign requested address          
        Is the server running on host "localhost" (::1) and accepting        
        TCP/IP connections on port 5432?    

I tried Doctrine's syntax, raw PDO syntax, do not have idea. Is there a possibility that my pdo_pgsql does not have unix socket support compiled?

This is what I tried as database URL in Doctrine:

pdo-pgsql://yyyy:xxxxx@/var/run/postgresql:5432/zzzzz
pgsql:host=/var/run/postgresql;user=xxxx;dbname=zzzz;password=yyyy

Answers

After debugging Doctrine's driver I created a not-so-elegant solution, but nevertheless it is working, and can be improved upon.

I don't like accessing environment variable in the driver itself, but possibly this can be improved.

doctrine.yaml

doctrine:
    dbal:
        #driver:   %database_driver%
        driver_class: App\Infrastructure\Common\Service\PostgreSQLDoctrineDriver
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name%
        user:     %database_user%
        password: %database_password%
        #charset:  UTF8

    orm:
        auto_generate_proxy_classes: %kernel.debug%
        auto_mapping: true

PostgreSQLDoctrineDriver.php

<?php declare(strict_types=1);

namespace App\Infrastructure\Common\Service;

use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOPgSql\Driver;
use \PDO;
use \PDOException;
use function defined;

/**
 * Driver that connects through pdo_pgsql
 *
 * Forked original PostgreSQL driver, extended to have a possibility to pass raw PDO DSN to be
 * able to connect via Unix socket
 */
class PostgreSQLDoctrineDriver extends Driver
{
    /**
     * {@inheritdoc}
     */
    public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
    {
        try {
            $pdo = new PDOConnection(
                $_SERVER['POSTGRES_DB_PDO_DSN'] ?? '',
                $username,
                $password,
                $driverOptions
            );

            if (defined('PDO::PGSQL_ATTR_DISABLE_PREPARES')
                && (! isset($driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES])
                    || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true
                )
            ) {
                $pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true);
            }

            /* defining client_encoding via SET NAMES to avoid inconsistent DSN support
             * - the 'client_encoding' connection param only works with postgres >= 9.1
             * - passing client_encoding via the 'options' param breaks pgbouncer support
             */
            if (isset($params['charset'])) {
                $pdo->exec('SET NAMES \'' . $params['charset'] . '\'');
            }

            return $pdo;
        } catch (PDOException $e) {
            throw DBALException::driverException($this, $e);
        }
    }

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

PostgreSQL社区为您提供最前沿的新闻资讯和知识内容

更多推荐