fix : connect to target database for table count and largest table queries
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled

information_schema and pg_class only show tables from the current database.
Open a temporary connection to the target database for these queries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-04-08 16:20:57 +02:00
parent 838378a409
commit ce744b3aba

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Service;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
final class DatabaseService
{
@@ -28,7 +29,7 @@ final class DatabaseService
];
try {
// Check database exists
// Check database exists (cross-database query via system catalog)
$exists = $this->connection->fetchOne(
'SELECT 1 FROM pg_database WHERE datname = :dbname',
['dbname' => $databaseName]
@@ -38,33 +39,40 @@ final class DatabaseService
return $fallback;
}
// Database size
// Database size (cross-database, works from any connection)
$sizeBytes = (int) $this->connection->fetchOne(
'SELECT pg_database_size(:dbname)',
['dbname' => $databaseName]
);
$size = $this->formatBytes($sizeBytes);
// Table count
$tableCount = (int) $this->connection->fetchOne(
"SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = :dbname",
['dbname' => $databaseName]
);
// Active connections
// Active connections (cross-database system view)
$activeConnections = (int) $this->connection->fetchOne(
'SELECT count(*) FROM pg_stat_activity WHERE datname = :dbname',
['dbname' => $databaseName]
);
// Cache hit ratio
// Cache hit ratio (cross-database system view)
$cacheHitRatio = (float) ($this->connection->fetchOne(
'SELECT round(100.0 * sum(blks_hit) / nullif(sum(blks_hit + blks_read), 0), 2) FROM pg_stat_database WHERE datname = :dbname',
['dbname' => $databaseName]
) ?? 0);
// Largest table — requires querying the target database catalog
$largestTable = $this->fetchLargestTable($databaseName);
// Connect to the target database for table-specific queries
$targetConn = $this->connectToDatabase($databaseName);
try {
// Table count (must query target database's information_schema)
$tableCount = (int) $targetConn->fetchOne(
"SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = :dbname",
['dbname' => $databaseName]
);
// Largest table (must query target database's pg_class)
$largestTable = $this->fetchLargestTable($targetConn);
} finally {
$targetConn->close();
}
return [
'connected' => true,
@@ -80,15 +88,22 @@ final class DatabaseService
}
}
private function fetchLargestTable(string $databaseName): string
private function connectToDatabase(string $databaseName): Connection
{
$params = $this->connection->getParams();
$params['dbname'] = $databaseName;
return DriverManager::getConnection($params);
}
private function fetchLargestTable(Connection $conn): string
{
try {
$row = $this->connection->fetchAssociative(
$row = $conn->fetchAssociative(
"SELECT relname, pg_total_relation_size(c.oid) as total_size
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public' AND c.relkind = 'r'
AND c.relowner = (SELECT oid FROM pg_roles WHERE rolname = current_user)
ORDER BY pg_total_relation_size(c.oid) DESC
LIMIT 1"
);