Skip to content

Commit 7cdff89

Browse files
committed
BUG#34467201: Add init_command connection option
With this patch, support for the "inti_command" option is added as part of the connection settings. This new option allows the user to specify a command to be executed right after the connection is established, that's to say, as part of the connection initialization. Additionally, adding this option inside the Django database configuration when connection is established now works, previously this was ignored. Thanks Sander van de Graaf for the contribution. Change-Id: I24069cb071cdf388ebb543500c22db6d2c141d40
1 parent 093d559 commit 7cdff89

File tree

7 files changed

+78
-2
lines changed

7 files changed

+78
-2
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ v8.0.32
1919
- BUG#34675508: Character set 'utf8' unsupported in python mysql connector when using MariaDB
2020
- BUG#34556157: Kerberos authorization fails when using SSPI as security interface
2121
- BUG#34499578: MySQLCursor.executemany() fails to correctly identify BULK data loading ops
22+
- BUG#34467201: Add init_command connection option
2223
- BUG#32625155: Tests fail against group replication cluster
2324
- BUG#30089671: Fix decoding VARBINARY columns when using a prepared cursor
2425
- BUG#28020811: Fix multiple reference leaks in the C extension

lib/mysql/connector/abstracts.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ def __init__(self) -> None:
198198
self._compress: bool = False
199199

200200
self._consume_results: bool = False
201+
self._init_command: Optional[str] = None
201202

202203
def __enter__(self) -> MySQLConnectionAbstract:
203204
return self
@@ -611,6 +612,11 @@ def config(self, **kwargs: Any) -> None:
611612
if "ssl_disabled" in config:
612613
self._ssl_disabled = config.pop("ssl_disabled")
613614

615+
# If an init_command is set, keep it, so we can execute it in _post_connection
616+
if "init_command" in config:
617+
self._init_command = config["init_command"]
618+
del config["init_command"]
619+
614620
# Other configuration
615621
set_ssl_flag = False
616622
for key, value in config.items():
@@ -1149,6 +1155,8 @@ def _post_connection(self) -> None:
11491155
self.time_zone = self._time_zone
11501156
if self._sql_mode:
11511157
self.sql_mode = self._sql_mode
1158+
if self._init_command:
1159+
self._execute_query(self._init_command)
11521160

11531161
@abstractmethod
11541162
def disconnect(self) -> Any:

lib/mysql/connector/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"oci_config_file": None,
9393
"fido_callback": None,
9494
"kerberos_auth_mode": None,
95+
"init_command": None,
9596
}
9697

9798
CNX_POOL_ARGS: Tuple[str, str, str] = ("pool_name", "pool_size", "pool_reset_session")

lib/mysql/connector/django/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ def get_connection_params(self) -> Dict[str, Any]:
360360
kwargs["host"] = settings_dict["HOST"]
361361
if settings_dict["PORT"]:
362362
kwargs["port"] = int(settings_dict["PORT"])
363+
if settings_dict.get("OPTIONS", {}).get("init_command"):
364+
kwargs["init_command"] = settings_dict["OPTIONS"]["init_command"]
363365

364366
# Raise exceptions for database warnings if DEBUG is on
365367
kwargs["raise_on_warnings"] = settings.DEBUG

lib/mysql/connector/django/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ def settings_to_cmd_args_env(
6262
if defaults_file:
6363
args.append(f"--defaults-file={defaults_file}")
6464

65-
# We force SQL_MODE to TRADITIONAL
66-
args.append("--init-command=SET @@session.SQL_MODE=TRADITIONAL")
65+
# Load any custom init_commands. We always force SQL_MODE to TRADITIONAL
66+
init_command = settings_dict["OPTIONS"].get("init_command", "")
67+
args.append(f"--init-command=SET @@session.SQL_MODE=TRADITIONAL;{init_command}")
6768

6869
if user:
6970
args.append(f"--user={user}")

tests/test_bugs.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7300,3 +7300,33 @@ def test_batch_insert_happens_in_executemany(self):
73007300
),
73017301
"Batch insert failed!",
73027302
)
7303+
7304+
7305+
class BugOra34467201(tests.MySQLConnectorTests):
7306+
"""BUG#34467201: Add init_command connection option
7307+
7308+
With this patch, support for the inti_command option is added as
7309+
part of the connection settings. This new option allows the user to
7310+
specify a command to be executed right after the connection is
7311+
established, that's to say, as part of the connection initialization.
7312+
"""
7313+
7314+
var_name = "test_var"
7315+
var_value = "BugOra34467201"
7316+
7317+
def setUp(self):
7318+
config = tests.get_mysql_config()
7319+
config["init_command"] = f"SET @{self.var_name}='{self.var_value}'"
7320+
self.cnx = mysql.connector.connect(**config)
7321+
7322+
def tearDown(self):
7323+
with self.cnx.cursor() as cur:
7324+
cur.execute(f"SET @{self.var_name} = NULL")
7325+
self.cnx.close()
7326+
7327+
@foreach_cnx
7328+
def test_init_command(self):
7329+
with self.cnx.cursor() as cur:
7330+
cur.execute(f"SELECT @{self.var_name}")
7331+
res = cur.fetchall()
7332+
self.assertEqual((self.var_value,), res[0])

tests/test_django.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,36 @@ def test_safe_string(self):
575575
)
576576
self.cur.execute("SELECT col1, col2 FROM {0}".format(self.tbl), ())
577577
self.assertEqual(self.cur.fetchall(), [(safe_text, safe_bytes.encode())])
578+
579+
580+
class BugOra34467201(tests.MySQLConnectorTests):
581+
"""BUG#34467201: Add init_command connection option
582+
583+
With this patch, support for the inti_command option is added as
584+
part of the connection settings. This new option allows the user to
585+
specify a command to be executed right after the connection is
586+
established, that's to say, as part of the connection initialization.
587+
"""
588+
589+
var_name = "test_var"
590+
var_value = "BugOra34467201"
591+
592+
def setUp(self):
593+
settings.DATABASES["default"]["OPTIONS"] = {
594+
"init_command": f"SET @{self.var_name}='{self.var_value}'"
595+
}
596+
dbconfig = tests.get_mysql_config()
597+
self.conn = mysql.connector.connect(**dbconfig)
598+
self.cnx = DatabaseWrapper(settings.DATABASES["default"])
599+
600+
def tearDown(self):
601+
with self.cnx.cursor() as cur:
602+
cur.execute(f"SET @{self.var_name} = NULL")
603+
self.cnx.close()
604+
del settings.DATABASES["default"]["OPTIONS"]
605+
606+
def test_init_command(self):
607+
with self.cnx.cursor() as cur:
608+
cur.execute(f"SELECT @{self.var_name}")
609+
res = cur.fetchall()
610+
self.assertEqual((self.var_value,), res[0])

0 commit comments

Comments
 (0)