diff --git a/frappe/tests/test_perf.py b/frappe/tests/test_perf.py index d4fc933571..e05fb03f82 100644 --- a/frappe/tests/test_perf.py +++ b/frappe/tests/test_perf.py @@ -16,6 +16,8 @@ query. This test can be written like this. >>> get_controller("User") """ +import gc +import sys import time from unittest.mock import patch @@ -176,3 +178,18 @@ class TestPerformance(FrappeTestCase): query = frappe.get_all("DocType", {"autoname": ("is", "set")}, run=0).lower() self.assertNotIn("coalesce", query) self.assertNotIn("ifnull", query) + + def test_no_stale_ref_sql(self): + """frappe.db.sql should not hold any internal references to result set. + + pymysql stores results internally. If your code reads a lot and doesn't make another + query, for that entire duration there's copy of result consuming memory in internal + attributes of pymysql. + We clear it manually, this test ensures that it actually works. + """ + + query = "select * from tabUser" + for kwargs in ({}, {"as_dict": True}, {"as_list": True}): + result = frappe.db.sql(query, **kwargs) + self.assertEqual(sys.getrefcount(result), 2) # Note: This always returns +1 + self.assertFalse(gc.get_referrers(result))