2021-05-19 18:07:42 +02:00
|
|
|
""" MySQL client """
|
|
|
|
|
|
|
|
import logging
|
|
|
|
import sys
|
|
|
|
|
|
|
|
import MySQLdb
|
2023-01-06 19:36:14 +01:00
|
|
|
from MySQLdb._exceptions import Error
|
2021-05-19 18:07:42 +02:00
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
from mylib.db import DB, DBFailToConnect
|
2023-01-07 02:19:18 +01:00
|
|
|
|
2021-05-19 18:07:42 +02:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2021-05-19 19:19:57 +02:00
|
|
|
|
2023-01-07 02:19:18 +01:00
|
|
|
class MyDB(DB):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""MySQL client"""
|
2021-05-19 18:07:42 +02:00
|
|
|
|
2023-01-07 02:19:18 +01:00
|
|
|
_host = None
|
|
|
|
_user = None
|
|
|
|
_pwd = None
|
|
|
|
_db = None
|
2021-05-19 18:07:42 +02:00
|
|
|
|
2023-01-07 02:19:18 +01:00
|
|
|
def __init__(self, host, user, pwd, db, charset=None, **kwargs):
|
|
|
|
self._host = host
|
|
|
|
self._user = user
|
|
|
|
self._pwd = pwd
|
|
|
|
self._db = db
|
2023-01-16 12:56:12 +01:00
|
|
|
self._charset = charset if charset else "utf8"
|
2023-01-07 02:19:18 +01:00
|
|
|
super().__init__(**kwargs)
|
2021-05-19 18:07:42 +02:00
|
|
|
|
2023-01-07 02:19:18 +01:00
|
|
|
def connect(self, exit_on_error=True):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Connect to MySQL server"""
|
2023-01-07 02:19:18 +01:00
|
|
|
if self._conn is None:
|
2021-05-19 18:07:42 +02:00
|
|
|
try:
|
2023-01-07 02:19:18 +01:00
|
|
|
self._conn = MySQLdb.connect(
|
2023-01-16 12:56:12 +01:00
|
|
|
host=self._host,
|
|
|
|
user=self._user,
|
|
|
|
passwd=self._pwd,
|
|
|
|
db=self._db,
|
|
|
|
charset=self._charset,
|
|
|
|
use_unicode=True,
|
|
|
|
)
|
2023-01-07 02:19:18 +01:00
|
|
|
except Error as err:
|
|
|
|
log.fatal(
|
2024-03-15 09:52:23 +01:00
|
|
|
"An error occurred during MySQL database connection (%s@%s:%s).",
|
2023-01-16 12:56:12 +01:00
|
|
|
self._user,
|
|
|
|
self._host,
|
|
|
|
self._db,
|
|
|
|
exc_info=1,
|
2023-01-07 02:19:18 +01:00
|
|
|
)
|
|
|
|
if exit_on_error:
|
|
|
|
sys.exit(1)
|
|
|
|
else:
|
2023-01-16 12:56:12 +01:00
|
|
|
raise DBFailToConnect(f"{self._user}@{self._host}:{self._db}") from err
|
2023-01-07 02:19:18 +01:00
|
|
|
return True
|
|
|
|
|
|
|
|
def doSQL(self, sql, params=None):
|
|
|
|
"""
|
|
|
|
Run SQL query and commit changes (rollback on error)
|
|
|
|
|
|
|
|
:param sql: The SQL query
|
|
|
|
:param params: The SQL query's parameters as dict (optional)
|
|
|
|
|
|
|
|
:return: True on success, False otherwise
|
|
|
|
:rtype: bool
|
|
|
|
"""
|
|
|
|
if self.just_try:
|
|
|
|
log.debug("Just-try mode : do not really execute SQL query '%s'", sql)
|
|
|
|
return True
|
|
|
|
cursor = self._conn.cursor()
|
2021-05-19 18:07:42 +02:00
|
|
|
try:
|
2023-01-07 02:19:18 +01:00
|
|
|
self._log_query(sql, params)
|
|
|
|
cursor.execute(sql, params)
|
|
|
|
self._conn.commit()
|
2021-05-19 18:07:42 +02:00
|
|
|
return True
|
2023-01-06 19:36:14 +01:00
|
|
|
except Error:
|
2023-01-07 02:19:18 +01:00
|
|
|
self._log_query_exception(sql, params)
|
|
|
|
self._conn.rollback()
|
2021-05-19 18:07:42 +02:00
|
|
|
return False
|
|
|
|
|
2023-01-07 02:19:18 +01:00
|
|
|
def doSelect(self, sql, params=None):
|
|
|
|
"""
|
|
|
|
Run SELECT SQL query and return list of selected rows as dict
|
|
|
|
|
|
|
|
:param sql: The SQL query
|
|
|
|
:param params: The SQL query's parameters as dict (optional)
|
|
|
|
|
|
|
|
:return: List of selected rows as dict on success, False otherwise
|
|
|
|
:rtype: list, bool
|
|
|
|
"""
|
2021-05-19 18:07:42 +02:00
|
|
|
try:
|
2023-01-07 02:19:18 +01:00
|
|
|
self._log_query(sql, params)
|
|
|
|
cursor = self._conn.cursor()
|
|
|
|
cursor.execute(sql, params)
|
|
|
|
return [
|
2023-01-16 12:56:12 +01:00
|
|
|
{field[0]: row[idx] for idx, field in enumerate(cursor.description)}
|
2023-01-07 02:19:18 +01:00
|
|
|
for row in cursor.fetchall()
|
|
|
|
]
|
2023-01-06 19:36:14 +01:00
|
|
|
except Error:
|
2023-01-07 02:19:18 +01:00
|
|
|
self._log_query_exception(sql, params)
|
2021-05-19 18:07:42 +02:00
|
|
|
return False
|
2023-01-07 02:19:18 +01:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _quote_table_name(table):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Quote table name"""
|
|
|
|
return "`{}`".format( # pylint: disable=consider-using-f-string
|
|
|
|
"`.`".join(table.split("."))
|
2023-01-07 02:19:18 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _quote_field_name(field):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Quote table name"""
|
|
|
|
return f"`{field}`"
|