Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/DDTrace/Integrations/PDO/PDOIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Unescape libpq-quoted dbnames before tagging

When a valid pgsql DSN uses libpq escaping inside the quoted dbname, this only removes the outer quotes and leaves escape characters in the tag. For example pgsql:dbname='customer\'s db' connects to database customer's db, but the span now emits db.name=customer\'s db, so peer-service/db-name identity is still split for quoted database names containing a quote or backslash. After stripping libpq-style quotes, the escaped \' and \\ sequences need to be decoded as libpq does.

Useful? React with 👍 / 👎.

}
if ($db !== "") {
$tags[Tag::DB_NAME] = $db;
}
Expand Down
31 changes: 31 additions & 0 deletions tests/Integrations/PDO/PDOTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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'],
];
}
}
Loading