diff --git a/src/DDTrace/Integrations/PDO/PDOIntegration.php b/src/DDTrace/Integrations/PDO/PDOIntegration.php index f731bdc3df..73e646c8f9 100644 --- a/src/DDTrace/Integrations/PDO/PDOIntegration.php +++ b/src/DDTrace/Integrations/PDO/PDOIntegration.php @@ -247,6 +247,10 @@ private static function parseDsn($dsn) $tags[Tag::DB_SYSTEM] = $dbSystem; $tags[Tag::DB_TYPE] = $dbSystem; // db.type is DD equivalent to db.system in OpenTelemetry, used for SQL spans obfuscation + // Match libpq: strip paired wrapping single quotes from dbname (APMS-19464). + if (strlen($db) >= 2 && $db[0] === "'" && substr($db, -1) === "'") { + $db = substr($db, 1, -1); + } if ($db !== "") { $tags[Tag::DB_NAME] = $db; } diff --git a/tests/Integrations/PDO/PDOTest.php b/tests/Integrations/PDO/PDOTest.php index a4bfe816ab..dd77c79047 100644 --- a/tests/Integrations/PDO/PDOTest.php +++ b/tests/Integrations/PDO/PDOTest.php @@ -2,9 +2,11 @@ namespace DDTrace\Tests\Integrations\PDO; +use DDTrace\Integrations\PDO\PDOIntegration; use DDTrace\Tag; use DDTrace\Tests\Common\IntegrationTestCase; use DDTrace\Tests\Common\SpanAssertion; +use ReflectionMethod; use function DDTrace\close_span; use function DDTrace\start_trace_span; @@ -907,4 +909,33 @@ protected function baseTags($expectPeerService = false) return $tags; } + + /** + * @dataProvider dsnDbNameCases + */ + public function testParseDsnDbNameQuoteHandling($dsn, $expectedDbName) + { + $method = new ReflectionMethod(PDOIntegration::class, 'parseDsn'); + $method->setAccessible(true); + $tags = $method->invoke(null, $dsn); + + if ($expectedDbName === null) { + $this->assertArrayNotHasKey(Tag::DB_NAME, $tags); + } else { + $this->assertSame($expectedDbName, $tags[Tag::DB_NAME]); + } + } + + public function dsnDbNameCases() + { + return [ + 'unquoted dbname' => ['pgsql:host=h;dbname=milk', 'milk'], + 'paired single quotes stripped' => ["pgsql:host=h;dbname='milk'", 'milk'], + 'double quotes preserved as-is' => ['pgsql:host=h;dbname="milk"', '"milk"'], + 'unpaired leading quote preserved' => ["pgsql:host=h;dbname='milk", "'milk"], + 'unpaired trailing quote preserved' => ["pgsql:host=h;dbname=milk'", "milk'"], + 'empty quoted dbname omitted' => ["pgsql:host=h;dbname=''", null], + 'database= alias also stripped' => ["mysql:host=h;database='foo'", 'foo'], + ]; + } }