Skip to content

Commit 27b7ef8

Browse files
committed
WL#16015: Remove use of removed COM_ commands
The server worklog WL#13448 removes the mysql_refresh() function from the C library, along with several COM_XXX commands. This worklog removes the usage of mysql_refresh() C API function and changes how COM_REFRESH, and COM_PROCESS_KILL command functions are executed, by using SQL statements instead. Change-Id: I7ff55e352d9e60dce2dbefff3f528f2ceccc63d0
1 parent 60cf3f9 commit 27b7ef8

9 files changed

+139
-26
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Full release notes:
1111
v8.3.0
1212
======
1313

14+
- WL#16015: Remove use of removed COM_ commands
1415
- WL#15983: Stop using mysql_ssl_set api
1516
- WL#15982: Remove use of mysql_shutdown
1617

lib/mysql/connector/connection.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,14 @@
5757
from . import version
5858
from .abstracts import MySQLConnectionAbstract
5959
from .authentication import MySQLAuthenticator, get_auth_plugin
60-
from .constants import ClientFlag, FieldType, ServerCmd, ServerFlag, flag_is_set
60+
from .constants import (
61+
ClientFlag,
62+
FieldType,
63+
RefreshOption,
64+
ServerCmd,
65+
ServerFlag,
66+
flag_is_set,
67+
)
6168
from .conversion import MySQLConverter
6269
from .cursor import (
6370
CursorBase,
@@ -900,12 +907,33 @@ def cmd_refresh(self, options: int) -> OkPacketType:
900907
RefreshOption = mysql.connector.RefreshOption
901908
refresh = RefreshOption.LOG | RefreshOption.THREADS
902909
cnx.cmd_refresh(refresh)
903-
904-
The result is a dictionary with the OK packet information.
905-
906-
Returns a dict()
907910
"""
908-
return self._handle_ok(self._send_cmd(ServerCmd.REFRESH, int4store(options)))
911+
if not options & (
912+
RefreshOption.GRANT
913+
| RefreshOption.LOG
914+
| RefreshOption.TABLES
915+
| RefreshOption.HOST
916+
| RefreshOption.STATUS
917+
| RefreshOption.REPLICA
918+
):
919+
raise ValueError("Invalid command REFRESH option")
920+
921+
if options & RefreshOption.GRANT:
922+
res = self.cmd_query("FLUSH PRIVILEGES")
923+
if options & RefreshOption.LOG:
924+
res = self.cmd_query("FLUSH LOGS")
925+
if options & RefreshOption.TABLES:
926+
res = self.cmd_query("FLUSH TABLES")
927+
if options & RefreshOption.HOST:
928+
res = self.cmd_query("TRUNCATE TABLE performance_schema.host_cache")
929+
if options & RefreshOption.STATUS:
930+
res = self.cmd_query("FLUSH STATUS")
931+
if options & RefreshOption.REPLICA:
932+
res = self.cmd_query(
933+
"RESET SLAVE" if self._server_version < (8, 0, 22) else "RESET REPLICA"
934+
)
935+
936+
return res
909937

910938
def cmd_quit(self) -> bytes:
911939
"""Close the current connection with the server
@@ -950,12 +978,10 @@ def cmd_process_kill(self, mysql_pid: int) -> OkPacketType:
950978
This method send the PROCESS_KILL command to the server along with
951979
the process ID. The result is a dictionary with the OK packet
952980
information.
953-
954-
Returns a dict()
955981
"""
956-
return self._handle_ok(
957-
self._send_cmd(ServerCmd.PROCESS_KILL, int4store(mysql_pid))
958-
)
982+
if not isinstance(mysql_pid, int):
983+
raise ValueError("MySQL PID must be int")
984+
return self.cmd_query(f"KILL {mysql_pid}")
959985

960986
def cmd_debug(self) -> EofPacketType:
961987
"""Send the DEBUG command

lib/mysql/connector/connection_cext.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ def cmd_process_kill(self, mysql_pid: int) -> None:
936936
"""Kill a MySQL process"""
937937
if not isinstance(mysql_pid, int):
938938
raise ValueError("MySQL PID must be int")
939-
self.info_query(f"KILL {mysql_pid}")
939+
self.cmd_query(f"KILL {mysql_pid}")
940940

941941
def cmd_debug(self) -> Any:
942942
"""Send the DEBUG command"""

lib/mysql/connector/constants.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,6 @@ class RefreshOption(_Constants, metaclass=RefreshOptionMeta):
644644
TABLES: int = 1 << 2
645645
HOST: int = 1 << 3
646646
STATUS: int = 1 << 4
647-
THREADS: int = 1 << 5
648647
REPLICA: int = 1 << 6
649648

650649
desc: Dict[str, Tuple[int, str]] = {
@@ -653,7 +652,6 @@ class RefreshOption(_Constants, metaclass=RefreshOptionMeta):
653652
"TABLES": (1 << 2, "close all tables"),
654653
"HOST": (1 << 3, "Flush host cache"),
655654
"STATUS": (1 << 4, "Flush status variables"),
656-
"THREADS": (1 << 5, "Flush thread cache"),
657655
"REPLICA": (1 << 6, "Reset source info and restart replica thread"),
658656
"SLAVE": (1 << 6, "Deprecated option; use REPLICA instead."),
659657
}

src/mysql_capi.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2884,18 +2884,59 @@ MySQL_num_fields(MySQL *self)
28842884
PyObject *
28852885
MySQL_refresh(MySQL *self, PyObject *args)
28862886
{
2887+
int res = 0;
2888+
int refresh_options_len = 0;
28872889
unsigned int options;
2888-
int res;
2890+
unsigned int supported_options = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 6;
2891+
unsigned long mysql_version;
2892+
char *reset_replica_stmt;
2893+
2894+
Py_BEGIN_ALLOW_THREADS
2895+
mysql_version = mysql_get_server_version(&self->session);
2896+
Py_END_ALLOW_THREADS
2897+
2898+
/* As of MySQL 8.0.22 REPLICA should be used instead of SLAVE */
2899+
reset_replica_stmt = mysql_version < 80022 ? "RESET SLAVE" : "RESET REPLICA";
2900+
2901+
/* A struct to represent the REFRESH options and their associated statements */
2902+
struct RefreshOption {
2903+
unsigned int option;
2904+
const char *statement;
2905+
};
2906+
2907+
/* Define an array of RefreshOption structs */
2908+
struct RefreshOption refresh_options[] = {
2909+
{1 << 0, "FLUSH PRIVILEGES"}, /* REFRESH_GRANT */
2910+
{1 << 1, "FLUSH LOGS"}, /* REFRESH_LOGS */
2911+
{1 << 2, "FLUSH TABLES"}, /* REFRESH_TABLES */
2912+
{1 << 3, "TRUNCATE TABLE performance_schema.host_cache"}, /* REFRESH_HOSTS */
2913+
{1 << 4, "FLUSH STATUS"}, /* REFRESH_STATUS */
2914+
{1 << 6, reset_replica_stmt} /* REFRESH_REPLICA */
2915+
};
28892916

28902917
IS_CONNECTED(self);
28912918

28922919
if (!PyArg_ParseTuple(args, "I", &options)) {
28932920
return NULL;
28942921
}
28952922

2896-
Py_BEGIN_ALLOW_THREADS
2897-
res = mysql_refresh(&self->session, options);
2898-
Py_END_ALLOW_THREADS
2923+
if (!(options & supported_options)) {
2924+
PyErr_SetString(PyExc_ValueError, "Invalid command REFRESH option");
2925+
return NULL;
2926+
}
2927+
2928+
refresh_options_len = (int)(sizeof(refresh_options) / sizeof(refresh_options[0]));
2929+
2930+
for (int i = 0; i < refresh_options_len; i++) {
2931+
if (options & refresh_options[i].option) {
2932+
res = mysql_real_query(&self->session,
2933+
refresh_options[i].statement,
2934+
strlen(refresh_options[i].statement));
2935+
if (res) {
2936+
break; /* stop processing if an error occurs */
2937+
}
2938+
}
2939+
}
28992940

29002941
if (res) {
29012942
raise_with_session(&self->session, NULL);

tests/cext/test_cext_connection.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Copyright (c) 2014, 2022, Oracle and/or its affiliates.
3+
# Copyright (c) 2014, 2023, Oracle and/or its affiliates.
44
#
55
# This program is free software; you can redistribute it and/or modify
66
# it under the terms of the GNU General Public License, version 2.0, as
@@ -38,7 +38,20 @@
3838
from mysql.connector import cursor, cursor_cext, errors
3939
from mysql.connector.connection import MySQLConnection
4040
from mysql.connector.connection_cext import CMySQLConnection
41-
from mysql.connector.constants import DEFAULT_CONFIGURATION, ClientFlag, flag_is_set
41+
from mysql.connector.constants import (
42+
DEFAULT_CONFIGURATION,
43+
ClientFlag,
44+
RefreshOption,
45+
flag_is_set,
46+
)
47+
48+
OK_PACKET_RESULT = {
49+
"insert_id": 0,
50+
"affected_rows": 0,
51+
"field_count": 0,
52+
"warning_count": 0,
53+
"server_status": 0,
54+
}
4255

4356

4457
class CMySQLConnectionTests(tests.MySQLConnectorTests):
@@ -152,6 +165,28 @@ def test_cmd_reset_connection(self):
152165
exp = (b"2",)
153166
self.assertNotEqual(exp, self.cnx.get_rows()[0][0])
154167

168+
def test_cmd_refresh(self):
169+
"""Send the Refresh-command to MySQL"""
170+
self.maxDiff = 2000
171+
refresh_options = (
172+
RefreshOption.GRANT,
173+
RefreshOption.LOG,
174+
RefreshOption.TABLES,
175+
RefreshOption.HOST,
176+
RefreshOption.STATUS,
177+
RefreshOption.REPLICA,
178+
)
179+
for option in refresh_options:
180+
self.assertEqual(OK_PACKET_RESULT, self.cnx.cmd_refresh(option))
181+
182+
# Test combined options
183+
options = RefreshOption.LOG | RefreshOption.STATUS
184+
self.assertEqual(OK_PACKET_RESULT, self.cnx.cmd_refresh(options))
185+
186+
def test_cmd_refresh_invalid_option(self):
187+
"""Test deprecated THREADS option"""
188+
self.assertRaises(ValueError, self.cnx.cmd_refresh, 1 << 5)
189+
155190
def test_connection_id(self):
156191
"""MySQL connection ID"""
157192
self.assertEqual(self.cnx._cmysql.thread_id(), self.cnx.connection_id)

tests/test_bugs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6846,7 +6846,7 @@ def test_cmd_refresh_with_consume_results(self):
68466846
res = cur.fetchone()
68476847
self.assertEqual(len(res), 2)
68486848
self.assertTrue(self.cnx.unread_result)
6849-
refresh = constants.RefreshOption.LOG | constants.RefreshOption.THREADS
6849+
refresh = constants.RefreshOption.LOG | constants.RefreshOption.STATUS
68506850
self.cnx.cmd_refresh(refresh)
68516851
self.assertFalse(self.cnx.unread_result)
68526852

tests/test_connection.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -572,11 +572,24 @@ def test_cmd_query_iter(self):
572572

573573
def test_cmd_refresh(self):
574574
"""Send the Refresh-command to MySQL"""
575-
self.cnx._socket.sock = tests.DummySocket()
576-
self.cnx._socket.sock.add_packet(OK_PACKET)
577-
refresh = constants.RefreshOption.LOG | constants.RefreshOption.THREADS
575+
refresh_options = (
576+
constants.RefreshOption.GRANT,
577+
constants.RefreshOption.LOG,
578+
constants.RefreshOption.TABLES,
579+
constants.RefreshOption.HOST,
580+
constants.RefreshOption.STATUS,
581+
constants.RefreshOption.REPLICA,
582+
)
583+
for option in refresh_options:
584+
self.assertEqual(OK_PACKET_RESULT, self.cnx.cmd_refresh(option))
585+
586+
# Test combined options
587+
options = constants.RefreshOption.LOG | constants.RefreshOption.STATUS
588+
self.assertEqual(OK_PACKET_RESULT, self.cnx.cmd_refresh(options))
578589

579-
self.assertEqual(OK_PACKET_RESULT, self.cnx.cmd_refresh(refresh))
590+
def test_cmd_refresh_invalid_option(self):
591+
"""Test deprecated THREADS option"""
592+
self.assertRaises(ValueError, self.cnx.cmd_refresh, 1 << 5)
580593

581594
def test_cmd_quit(self):
582595
"""Send the Quit-command to MySQL"""

tests/test_constants.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ class RefreshOptionTests(tests.MySQLConnectorTests):
558558
"REPLICA",
559559
"STATUS",
560560
"TABLES",
561-
"THREADS",
562561
"SLAVE",
563562
]
564563

0 commit comments

Comments
 (0)