in core/lib/payload/copy.py [0:0]
def kill_selects(self, table_names, conn=None):
"""
Kill current running SELECTs against the specified tables in the
working database so that they won't block the DDL statement we're
about to execute. The conn parameter allows to use a different
connection. A different connection is necessary when it is needed to
kill queries that may be blocking the current connection
"""
conn = conn or self.conn
table_names = [tbl.lower() for tbl in table_names]
# We use regex matching to find running queries on top of the tables
# Better options (as in more precise) would be:
# 1. List the current held metadata locks, but this is not possible
# without the performance schema
# 2. Actually parse the SQL of the running queries, but this can be
# quite expensive
keyword_pattern = (
r"(\s|^)" # whitespace or start
r"({})" # keyword(s)
r"(\s|$)" # whitespace or end
)
table_pattern = (
r"(\s|`)" # whitespace or backtick
r"({})" # table(s)
r"(\s|`|$)" # whitespace, backtick or end
)
alter_or_select_pattern = re.compile(keyword_pattern.format("select|alter"))
information_schema_pattern = re.compile(
keyword_pattern.format("information_schema")
)
any_tables_pattern = re.compile(table_pattern.format("|".join(table_names)))
processlist = conn.get_running_queries()
for proc in processlist:
sql_statement = proc.get("Info") or "".encode("utf-8")
sql_statement = sql_statement.decode("utf-8", "replace").lower()
if (
proc["db"] == self._current_db
and sql_statement
and not information_schema_pattern.search(sql_statement)
and any_tables_pattern.search(sql_statement)
and alter_or_select_pattern.search(sql_statement)
):
try:
conn.kill_query_by_id(int(proc["Id"]))
except MySQLdb.MySQLError as e:
errcode, errmsg = e.args
# 1094: Unknown thread id
# This means the query we were trying to kill has finished
# before we run kill %d
if errcode == 1094:
log.info(
"Trying to kill query id: {}, but it has "
"already finished".format(proc["Id"])
)
else:
raise