def reestablish_mysql_connection(cnx, attempt, delay): """Try to reconnect if it is not already connected. """ try: cnx.reconnect(attempt, delay) except (AttributeError, mysql.connector.errors.InterfaceError): raise _errors.DatabaseError("Invalid database connection.")
def wait_for_slave_gtid(server, gtids, timeout=0): """Wait until a slave executes GITDs. The function `SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS` is called until the slave catches up. If the timeout period expires prior to achieving the condition the :class:`~mysql.fabric.errors.TimeoutError` exception is raised. If any thread is stopped, the :class:`~mysql.fabric.errors.DatabaseError` exception is raised. :param server: MySQL Server. :param gtids: Gtid information. :param timeout: Timeout for waiting for slave to catch up. """ # Check servers for GTID support if not server.gtid_enabled: raise _errors.ProgrammingError( "Global Transaction IDs are not supported.") res = server.exec_stmt(_GTID_WAIT, {"params": (gtids, timeout)}) if res is None or res[0] is None or res[0][0] is None: raise _errors.DatabaseError("Error waiting for slave to catch up. " "GTID (%s)." % (gtids, )) elif res[0][0] == -1: raise _errors.TimeoutError("Error waiting for slave to catch up. " "GTID (%s)." % (gtids, )) assert (res[0][0] > -1)
def wait_for_slave(server, binlog_file, binlog_pos, timeout=0): """Wait for the slave to read the master's binlog up to a specified position. This methods call the MySQL function `SELECT MASTER_POS_WAIT`. If the timeout period expires prior to achieving the condition the :class:`~mysql.fabric.errors.TimeoutError` exception is raised. If any thread is stopped, the :class:`~mysql.fabric.errors.DatabaseError` exception is raised. :param server: MySQL Server. :param binlog_file: Master's binlog file. :param binlog_pos: Master's binlog file position. :param timeout: Maximum number of seconds to wait for the condition to be achieved. """ # Wait for slave to read the master log file res = server.exec_stmt(_MASTER_POS_WAIT, {"params": (binlog_file, binlog_pos, timeout)}) if res is None or res[0] is None or res[0][0] is None: raise _errors.DatabaseError( "Error waiting for slave to catch up. Binary log (%s, %s)." % (binlog_file, binlog_pos)) elif res[0][0] == -1: raise _errors.TimeoutError( "Error waiting for slave to catch up. Binary log (%s, %s)." % (binlog_file, binlog_pos)) assert (res[0][0] > -1)
def create_mysql_connection(**kwargs): """Create a connection. """ try: return mysql.connector.Connect(**kwargs) except mysql.connector.Error as error: raise _errors.DatabaseError(error)
def _check_condition(server, threads, check_if_running): """Check if slave's threads are either running or stopped. If the `SQL_THREAD` or the `IO_THREAD` are stopped and there is an error, the :class:`~mysql.fabric.errors.DatabaseError` exception is raised. :param server: MySQL Server. :param threads: Which threads should be checked. :type threads: `SQL_THREAD` or `IO_THREAD`. :param check_if_running: If one should check whether threads are running or stopped. :type check_if_running: Bool """ if not threads: threads = (SQL_THREAD, IO_THREAD) assert (isinstance(threads, tuple)) io_status = not check_if_running sql_status = not check_if_running check_stmt = "YES" if check_if_running else "NO" io_errno = sql_errno = 0 io_error = sql_error = "" ret = get_slave_status(server) if ret: io_status = ret[0].Slave_IO_Running.upper() == check_stmt io_error = ret[0].Last_IO_Error io_errno = ret[0].Last_IO_Errno io_errno = io_errno if io_errno else 0 sql_status = ret[0].Slave_SQL_Running.upper() == check_stmt sql_error = ret[0].Last_SQL_Error sql_errno = ret[0].Last_SQL_Errno sql_errno = sql_errno if sql_errno else 0 achieved = True if SQL_THREAD in threads: achieved = achieved and sql_status if check_if_running and sql_errno != 0: raise _errors.DatabaseError(sql_error) if IO_THREAD in threads: achieved = achieved and io_status if check_if_running and io_errno != 0: raise _errors.DatabaseError(io_error) return achieved
def destroy_mysql_connection(cnx): """Close the connection abruptly. Do not interact with the server. """ try: if cnx: cnx.disconnect() except Exception as error: raise _errors.DatabaseError( "Error trying to disconnect abruptly from (%s). %s." % (mysql_address_from_cnx(cnx), error))
def disconnect_mysql_connection(cnx): """Close the connection in a friendly way. Send a QUIT command. """ try: if cnx: cnx.disconnect() except Exception as error: raise _errors.DatabaseError( "Error trying to disconnect friendly from (%s). %s." % (mysql_address_from_cnx(cnx), error))
def connect_to_mysql(cnx=None, **kwargs): """Create a connection. """ try: if cnx is None: return mysql.connector.Connect(**kwargs) else: return cnx.connect(**kwargs) except mysql.connector.Error as error: raise _errors.DatabaseError(error)
def destroy_mysql_connection(cnx): """Close the connection. """ try: if cnx: cnx.shutdown() except Exception as error: raise _errors.DatabaseError( "Error trying to disconnect from (%s). %s." % (mysql_address_from_cnx(cnx), error))
def _check_status_condition(server, thread, status): """Check if a slave's thread has the requested status. If the `SQL_THREAD` or the `IO_THREAD` is stopped and there is an error, the following :class:`~mysql.fabric.errors.DatabaseError` exception is raised. :param server: MySQL Server. :param thread: Which thread should be checked. :type thread: `SQL_THREAD` or `IO_THREAD`. :param status: The status to be checked. """ io_errno = sql_errno = 0 io_error = sql_error = "" achieved = False ret = get_slave_status(server) if not ret: return achieved if SQL_THREAD == thread: sql_status = True if status in ret[0].Slave_SQL_Running_State else False sql_error = ret[0].Last_SQL_Error sql_errno = ret[0].Last_SQL_Errno if sql_errno and sql_errno != 0: raise _errors.DatabaseError(sql_error) achieved = sql_status elif IO_THREAD == thread: io_status = True if status in ret[0].Slave_IO_State else False io_error = ret[0].Last_IO_Error io_errno = ret[0].Last_IO_Errno if io_errno and io_errno != 0: raise _errors.DatabaseError(io_error) achieved = io_status return achieved
def exec_mysql_stmt(cnx, stmt_str, options=None): """Execute a statement for the client and return a result set or a cursor. This is the singular method to execute queries. If something goes wrong while executing a statement, the exception :class:`~mysql.fabric.errors.DatabaseError` is raised. :param cnx: Database connection. :param stmt_str: The statement (e.g. query, updates, etc) to execute. :param options: Options to control behavior: - params - Parameters for statement. - columns - If true, return a rows as named tuples (default is False). - raw - If true, do not convert MySQL's types to Python's types (default is True). - fetch - If true, execute the fetch as part of the operation (default is True). :return: Either a result set as list of tuples (either named or unnamed) or a cursor. """ if cnx is None: raise _errors.DatabaseError("Invalid database connection.") options = options or {} params = options.get('params', ()) columns = options.get('columns', False) fetch = options.get('fetch', True) raw = options.get('raw', False) if raw and columns: raise _errors.ProgrammingError( "No raw cursor available returning named tuple") _LOGGER.debug("Statement ({statement}, Params({parameters}).".format( statement=stmt_str.replace('\n', '').replace('\r', ''), parameters=params)) cur = None try: cur = cnx.cursor(raw=raw, named_tuple=columns) cur.execute(stmt_str, params) except Exception as error: if cnx.unread_result: cnx.get_rows() if cur: cur.close() errno = getattr(error, 'errno', None) raise _errors.DatabaseError( "Command (%s, %s) failed accessing (%s). %s." % (stmt_str, params, mysql_address_from_cnx(cnx), error), errno) assert (cur is not None) if fetch: results = None try: if cnx.unread_result: results = cur.fetchall() except mysql.connector.errors.InterfaceError as error: raise _errors.DatabaseError( "Command (%s, %s) failed fetching data from (%s). %s." % (stmt_str, params, mysql_address_from_cnx(cnx), error)) finally: cur.close() return results return cur