Skip to content

Commit 874e582

Browse files
aldrickdevaldrick.castro
and
aldrick.castro
authored
Fixed bug with no parameter prepared statements (#20243)
* Added bug fix * Pulled out the section needed to be tested * Added tests * Passing tests * Added changelog * Formatting --------- Co-authored-by: aldrick.castro <aldrick.castro@d>
1 parent d2f8df4 commit 874e582

File tree

3 files changed

+61
-8
lines changed

3 files changed

+61
-8
lines changed

postgres/changelog.d/20243.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed bug where we fail to explain parameterized queries that have no parameters

postgres/datadog_checks/postgres/explain_parameterized_queries.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
SELECT CARDINALITY(parameter_types) FROM pg_prepared_statements WHERE name = 'dd_{query_signature}'
2323
'''
2424

25-
EXECUTE_PREPARED_STATEMENT_QUERY = 'EXECUTE dd_{prepared_statement}({generic_values})'
25+
EXECUTE_PREPARED_STATEMENT_QUERY = 'EXECUTE dd_{prepared_statement}{parameters}'
2626

2727
EXPLAIN_QUERY = 'SELECT {explain_function}($stmt${statement}$stmt$)'
2828

@@ -143,20 +143,26 @@ def _get_number_of_parameters_for_prepared_statement(self, dbname, query_signatu
143143
)
144144
return rows[0][0] if rows else 0
145145

146+
@tracked_method(agent_check_getter=agent_check_getter)
147+
def _generate_prepared_statement_query(self, dbname: str, query_signature: str) -> str:
148+
parameters = ""
149+
num_params = self._get_number_of_parameters_for_prepared_statement(dbname, query_signature)
150+
151+
if num_params > 0:
152+
null_parameters = ','.join('null' for _ in range(num_params))
153+
parameters = f"({null_parameters})"
154+
155+
return EXECUTE_PREPARED_STATEMENT_QUERY.format(prepared_statement=query_signature, parameters=parameters)
156+
146157
@tracked_method(agent_check_getter=agent_check_getter)
147158
def _explain_prepared_statement(self, dbname, statement, obfuscated_statement, query_signature):
148-
null_parameter = ','.join(
149-
'null' for _ in range(self._get_number_of_parameters_for_prepared_statement(dbname, query_signature))
150-
)
151-
execute_prepared_statement_query = EXECUTE_PREPARED_STATEMENT_QUERY.format(
152-
prepared_statement=query_signature, generic_values=null_parameter
153-
)
159+
prepared_statement_query = self._generate_prepared_statement_query(dbname, query_signature)
154160
try:
155161
return self._execute_query_and_fetch_rows(
156162
dbname,
157163
EXPLAIN_QUERY.format(
158164
explain_function=self._explain_function,
159-
statement=execute_prepared_statement_query,
165+
statement=prepared_statement_query,
160166
),
161167
)
162168
except Exception as e:

postgres/tests/test_explain_parameterized_queries.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,52 @@ def test_explain_parameterized_queries_explain_prepared_statement_no_plan_return
191191
assert err is None
192192

193193

194+
@pytest.mark.unit
195+
def test_generate_prepared_statement_query_no_parameters(integration_check, dbm_instance):
196+
check = integration_check(dbm_instance)
197+
check._connect()
198+
test_query_signature = "12345678"
199+
200+
check.check(dbm_instance)
201+
if check.version < V12:
202+
return
203+
204+
with mock.patch(
205+
'datadog_checks.postgres.explain_parameterized_queries.ExplainParameterizedQueries._get_number_of_parameters_for_prepared_statement',
206+
return_value=0,
207+
):
208+
209+
prepared_statement_query = (
210+
check.statement_samples._explain_parameterized_queries._generate_prepared_statement_query(
211+
DB_NAME, test_query_signature
212+
)
213+
)
214+
assert prepared_statement_query == f"EXECUTE dd_{test_query_signature}"
215+
216+
217+
@pytest.mark.unit
218+
def test_generate_prepared_statement_query_three_parameters(integration_check, dbm_instance):
219+
check = integration_check(dbm_instance)
220+
check._connect()
221+
test_query_signature = "12345678"
222+
223+
check.check(dbm_instance)
224+
if check.version < V12:
225+
return
226+
227+
with mock.patch(
228+
'datadog_checks.postgres.explain_parameterized_queries.ExplainParameterizedQueries._get_number_of_parameters_for_prepared_statement',
229+
return_value=3,
230+
):
231+
232+
prepared_statement_query = (
233+
check.statement_samples._explain_parameterized_queries._generate_prepared_statement_query(
234+
DB_NAME, test_query_signature
235+
)
236+
)
237+
assert prepared_statement_query == f"EXECUTE dd_{test_query_signature}(null,null,null)"
238+
239+
194240
@pytest.mark.integration
195241
def test_create_prepared_statement_exception(integration_check, dbm_instance):
196242
check = integration_check(dbm_instance)

0 commit comments

Comments
 (0)