Fixed #33715 -- Allowed keyboard interrupt to abort queries in MySQL dbshell.
This commit is contained in:
parent
e89f957135
commit
1a78ef2b85
|
@ -1,3 +1,5 @@
|
||||||
|
import signal
|
||||||
|
|
||||||
from django.db.backends.base.client import BaseDatabaseClient
|
from django.db.backends.base.client import BaseDatabaseClient
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,3 +60,13 @@ class DatabaseClient(BaseDatabaseClient):
|
||||||
args += [database]
|
args += [database]
|
||||||
args.extend(parameters)
|
args.extend(parameters)
|
||||||
return args, env
|
return args, env
|
||||||
|
|
||||||
|
def runshell(self, parameters):
|
||||||
|
sigint_handler = signal.getsignal(signal.SIGINT)
|
||||||
|
try:
|
||||||
|
# Allow SIGINT to pass to mysql to abort queries.
|
||||||
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
super().runshell(parameters)
|
||||||
|
finally:
|
||||||
|
# Restore the original SIGINT handler.
|
||||||
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from unittest import mock, skipUnless
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
from django.db.backends.mysql.client import DatabaseClient
|
from django.db.backends.mysql.client import DatabaseClient
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase
|
||||||
|
|
||||||
|
@ -218,3 +221,19 @@ class MySqlDbshellCommandTestCase(SimpleTestCase):
|
||||||
with self.assertRaises(subprocess.CalledProcessError) as ctx:
|
with self.assertRaises(subprocess.CalledProcessError) as ctx:
|
||||||
subprocess.run(args, check=True, env=env)
|
subprocess.run(args, check=True, env=env)
|
||||||
self.assertNotIn("somepassword", str(ctx.exception))
|
self.assertNotIn("somepassword", str(ctx.exception))
|
||||||
|
|
||||||
|
@skipUnless(connection.vendor == "mysql", "Requires a MySQL connection")
|
||||||
|
def test_sigint_handler(self):
|
||||||
|
"""SIGINT is ignored in Python and passed to mysql to abort queries."""
|
||||||
|
|
||||||
|
def _mock_subprocess_run(*args, **kwargs):
|
||||||
|
handler = signal.getsignal(signal.SIGINT)
|
||||||
|
self.assertEqual(handler, signal.SIG_IGN)
|
||||||
|
|
||||||
|
sigint_handler = signal.getsignal(signal.SIGINT)
|
||||||
|
# The default handler isn't SIG_IGN.
|
||||||
|
self.assertNotEqual(sigint_handler, signal.SIG_IGN)
|
||||||
|
with mock.patch("subprocess.run", new=_mock_subprocess_run):
|
||||||
|
connection.client.runshell([])
|
||||||
|
# dbshell restores the original handler.
|
||||||
|
self.assertEqual(sigint_handler, signal.getsignal(signal.SIGINT))
|
||||||
|
|
Loading…
Reference in New Issue