Skip to content

Commit 855e19a

Browse files
jasonmp85claude
andauthored
postgres: improve robustness of database name handling in schema collection (DataDog#23389)
* Improve robustness of database name handling in schema collection Switch `_get_databases` to use `%s` parameterized placeholders passed to `cursor.execute` instead of formatting values directly into the query string. This applies to the autodiscovery IN clause as well as the exclude/include regex filters, ensuring database names and filter patterns are always properly handled regardless of their content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add changelog entry for query parameterization fix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Escape percent literal in DATABASE_INFORMATION_QUERY for parameterized execution psycopg treats % as a placeholder prefix whenever params are passed to cursor.execute. The LIKE wildcard in the base query must be %% so it renders as a literal % after substitution. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Simplify _get_databases query construction Build query and params before acquiring the connection, flatten autodiscovery nesting, and use list multiplication for placeholder generation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d7f8f86 commit 855e19a

2 files changed

Lines changed: 22 additions & 16 deletions

File tree

postgres/changelog.d/23389.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix database name handling in schema collection query construction.

postgres/datadog_checks/postgres/schemas.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class PostgresDatabaseObject(DatabaseObject):
162162
FROM pg_catalog.pg_database db
163163
JOIN pg_roles a
164164
ON datdba = a.oid
165-
WHERE datname NOT LIKE 'template%'
165+
WHERE datname NOT LIKE 'template%%'
166166
"""
167167

168168

@@ -201,23 +201,28 @@ def kind(self):
201201
return "pg_databases"
202202

203203
def _get_databases(self):
204+
query = DATABASE_INFORMATION_QUERY
205+
params: list[str] = []
206+
207+
for exclude_regex in self._config.exclude_databases:
208+
query += " AND datname !~ %s"
209+
params.append(exclude_regex)
210+
211+
if self._config.include_databases:
212+
or_clause = " OR ".join(["datname ~ %s"] * len(self._config.include_databases))
213+
query += f" AND ({or_clause})"
214+
params.extend(self._config.include_databases)
215+
216+
# Autodiscovery trumps exclude and include
217+
autodiscovery_databases = self._check.autodiscovery.get_items() if self._check.autodiscovery else []
218+
if autodiscovery_databases:
219+
in_clause = ", ".join(["%s"] * len(autodiscovery_databases))
220+
query += f" AND datname IN ({in_clause})"
221+
params.extend(autodiscovery_databases)
222+
204223
with self._check._get_main_db() as conn:
205224
with conn.cursor(row_factory=dict_row) as cursor:
206-
query = DATABASE_INFORMATION_QUERY
207-
for exclude_regex in self._config.exclude_databases:
208-
query += " AND datname !~ '{}'".format(exclude_regex)
209-
if self._config.include_databases:
210-
query += f" AND ({
211-
' OR '.join(f"datname ~ '{include_regex}'" for include_regex in self._config.include_databases)
212-
})"
213-
214-
# Autodiscovery trumps exclude and include
215-
if self._check.autodiscovery:
216-
autodiscovery_databases = self._check.autodiscovery.get_items()
217-
if autodiscovery_databases:
218-
query += " AND datname IN ({})".format(", ".join(f"'{db}'" for db in autodiscovery_databases))
219-
220-
cursor.execute(query)
225+
cursor.execute(query, params)
221226
return [dict(row) for row in cursor.fetchall()]
222227

223228
@contextlib.contextmanager

0 commit comments

Comments
 (0)