Пример #1
0
    def send_compressed(self, buf, packet_number=None):
        """Send compressed packets to the MySQL server"""
        if packet_number is None:
            self.next_packet_number  # pylint: disable=W0104
        else:
            self._packet_number = packet_number
        pktnr = self._packet_number
        pllen = len(buf)
        zpkts = []
        maxpktlen = constants.MAX_PACKET_LENGTH
        if pllen > maxpktlen:
            pkts = _prepare_packets(buf, pktnr)
            tmpbuf = ''.join(pkts)
            del pkts
            seqid = 0
            zbuf = zlib.compress(tmpbuf[:16384])
            zpkts.append(
                struct.pack('<I', len(zbuf))[0:3] + struct.pack('<B', seqid) +
                '\x00\x40\x00' + zbuf)
            tmpbuf = tmpbuf[16384:]
            pllen = len(tmpbuf)
            seqid = seqid + 1
            while pllen > maxpktlen:
                zbuf = zlib.compress(tmpbuf[:maxpktlen])
                zpkts.append(
                    struct.pack('<I', len(zbuf))[0:3] +
                    struct.pack('<B', seqid) + '\xff\xff\xff' + zbuf)
                tmpbuf = tmpbuf[maxpktlen:]
                pllen = len(tmpbuf)
                seqid = seqid + 1
            if tmpbuf:
                zbuf = zlib.compress(tmpbuf)
                zpkts.append(
                    struct.pack('<I', len(zbuf))[0:3] +
                    struct.pack('<B', seqid) + struct.pack('<I', pllen)[0:3] +
                    zbuf)
            del tmpbuf
        else:
            pkt = (struct.pack('<I', pllen)[0:3] + struct.pack('<B', pktnr) +
                   buf)
            pllen = len(pkt)
            if pllen > 50:
                zbuf = zlib.compress(pkt)
                zpkts.append(
                    struct.pack('<I', len(zbuf))[0:3] + struct.pack('<B', 0) +
                    struct.pack('<I', pllen)[0:3] + zbuf)
            else:
                zpkts.append(
                    struct.pack('<I', pllen)[0:3] + struct.pack('<B', 0) +
                    struct.pack('<I', 0)[0:3] + pkt)

        for zip_packet in zpkts:
            try:
                self.sock.sendall(zip_packet)
            except IOError as err:
                raise errors.OperationalError(errno=2055,
                                              values=(self.get_address(),
                                                      _strioerror(err)))
            except AttributeError:
                raise errors.OperationalError(errno=2006)
Пример #2
0
    def _send_data(self, data_file, send_empty_packet=False):
        """Send data to the MySQL server

        This method accepts a file-like object and sends its data
        as is to the MySQL server. If the send_empty_packet is
        True, it will send an extra empty package (for example
        when using LOAD LOCAL DATA INFILE).

        Returns a MySQL packet.
        """
        if self.unread_result:
            raise errors.InternalError("Unread result found.")

        if not hasattr(data_file, 'read'):
            raise ValueError("expecting a file-like object")

        try:
            buf = data_file.read(NET_BUFFER_LENGTH - 16)
            while buf:
                yield from self._socket.drain()
                self._socket.send(buf)
                buf = data_file.read(NET_BUFFER_LENGTH - 16)
        except AttributeError:
            raise errors.OperationalError("MySQL Connection not available.")

        if send_empty_packet:
            try:
                yield from self._socket.drain()
                self._socket.send(b'')
            except AttributeError:
                raise errors.OperationalError(
                    "MySQL Connection not available.")
        return (yield from self._socket.recv())
Пример #3
0
 def send_plain(self, buf, packet_number=None):
     """Send packets to the MySQL server"""
     if packet_number is None:
         self.next_packet_number  # pylint: disable=W0104
     else:
         self._packet_number = packet_number
     packets = _prepare_packets(buf, self._packet_number)
     for packet in packets:
         try:
             self.sock.sendall(packet)
         except IOError as err:
             raise errors.OperationalError(
                 errno=2055, values=(self.get_address(), _strioerror(err)))
         except AttributeError:
             raise errors.OperationalError(errno=2006)
Пример #4
0
def get_pool_conn_implicitly(_db_config):
    """
    :param _db_config:
    :return:
    """
    config = _db_config
    if 'pool' not in config:
        pool = None
    else:
        pool = config['pool']
        if 'use' not in pool:
            raise errors.OperationalError("MySQL pool config error"
                                          " must pool key use")
        if 'size' not in pool:
            raise errors.OperationalError("MySQL pool config error"
                                          " must pool key size")
        if 'name' not in pool:
            raise errors.OperationalError("MySQL pool config error "
                                          "must pool key name")

    if pool and pool['use']:
        conn = PyMysqlPool.mysql.connector.connect(pool_name=pool['name'],
                                                   pool_size=pool['size'],
                                                   host=config['host'],
                                                   port=config['port'],
                                                   user=config['user'],
                                                   passwd=config['passwd'],
                                                   db=config['db'],
                                                   charset=config['charset'],
                                                   use_unicode=True,
                                                   connect_timeout=1000)
        conn.set_converter_class(FuzzyMySQLConverter)
    else:
        conn = MySQLdb.connect(host=config['host'],
                               port=config['port'],
                               user=config['user'],
                               passwd=config['passwd'],
                               db=config['db'],
                               charset=config['charset'],
                               use_unicode=True)

    conn.start_transaction(
        consistent_snapshot=config.get('consistent_snapshot', False),
        isolation_level=config.get('isolation_level', None),
        readonly=config.get('readonly', None),
    )

    return conn
Пример #5
0
    def _send_cmd(self, command, argument=None, packet_number=0, packet=None,
                  expect_response=True):
        """Send a command to the MySQL server

        This method sends a command with an optional argument.
        If packet is not None, it will be sent and the argument will be
        ignored.

        The packet_number is optional and should usually not be used.

        Some commands might not result in the MySQL server returning
        a response. If a command does not return anything, you should
        set expect_response to False. The _send_cmd method will then
        return None instead of a MySQL packet.

        Returns a MySQL packet or None.
        """
        if self.unread_result:
            raise errors.InternalError("Unread result found.")

        try:
            yield from self._socket.drain()
            self._socket.send(
                self._protocol.make_command(command, packet or argument),
                packet_number)
        except AttributeError:
            raise errors.OperationalError("MySQL Connection not available.")

        if not expect_response:
            return None

        return (yield from self._socket.recv())
Пример #6
0
    def cmd_stmt_send_long_data(self, statement_id, param_id, data):
        """Send data for a column

        This methods send data for a column (for example BLOB) for statement
        identified by statement_id. The param_id indicate which parameter
        the data belongs too.
        The data argument should be a file-like object.

        Since MySQL does not send anything back, no error is raised. When
        the MySQL server is not reachable, an OperationalError is raised.

        cmd_stmt_send_long_data should be called before cmd_stmt_execute.

        The total bytes send is returned.

        Returns int.
        """
        chunk_size = 8192
        total_sent = 0
        # pylint: disable=W0212
        prepare_packet = self._protocol._prepare_stmt_send_long_data
        # pylint: enable=W0212
        try:
            buf = data.read(chunk_size)
            while buf:
                packet = prepare_packet(statement_id, param_id, buf)
                yield from self._send_cmd(ServerCmd.STMT_SEND_LONG_DATA, packet=packet,
                                          expect_response=False)
                total_sent += len(buf)
                buf = data.read(chunk_size)
        except AttributeError:
            raise errors.OperationalError("MySQL Connection not available.")

        return total_sent
    def recv_plain(self):
        """Receive packets from the MySQL server"""
        try:
            # Read the header of the MySQL packet, 4 bytes
            packet = yield from self._reader.readexactly(4)

            # Save the packet number and payload length
            self._packet_number = packet[3]
            payload_len = struct.unpack("<I", packet[0:3] + b'\x00')[0]

            # Read the payload
            rest = payload_len
            spacket = packet
            packet = bytearray(4 + payload_len)
            packet[:4] = spacket
            packet_view = memoryview(packet)  # pylint: disable=E0602
            packet_view = packet_view[4:]
            while rest:
                read = yield from self._reader.read(rest)
                lrd = len(read)
                if lrd == 0 and rest > 0:
                    raise errors.InterfaceError(errno=2013)
                packet_view[:lrd] = read
                packet_view = packet_view[lrd:]
                rest -= lrd
            return packet
        except IOError as err:
            raise errors.OperationalError(errno=2055,
                                          values=(self.get_address(),
                                                  _strioerror(err)))
Пример #8
0
    def recv_plain(self):
        """Receive packets from the MySQL server"""
        packet = ''
        try:
            # Read the header of the MySQL packet, 4 bytes
            packet = self.sock.recv(1)
            while len(packet) < 4:
                chunk = self.sock.recv(1)
                if not chunk:
                    raise errors.InterfaceError(errno=2013)
                packet += chunk

            # Save the packet number and total packet length from header
            self._packet_number = ord(packet[3])
            packet_totlen = struct.unpack("<I", packet[0:3] + '\x00')[0] + 4

            # Read the rest of the packet
            rest = packet_totlen - len(packet)
            while rest > 0:
                chunk = self.sock.recv(rest)
                if not chunk:
                    raise errors.InterfaceError(errno=2013)
                packet += chunk
                rest = packet_totlen - len(packet)

            return packet
        except IOError as err:
            raise errors.OperationalError(errno=2055,
                                          values=(self.get_address(),
                                                  _strioerror(err)))
Пример #9
0
    def recv_compressed(self):
        """Receive compressed packets from the MySQL server"""
        try:
            return self._packet_queue.popleft()
        except IndexError:
            pass

        header = ''
        packets = []
        try:
            abyte = self.sock.recv(1)
            while abyte and len(header) < 7:
                header += abyte
                abyte = self.sock.recv(1)
            while header:
                if len(header) < 7:
                    raise errors.InterfaceError(errno=2013)
                zip_payload_length = struct.unpack("<I",
                                                   header[0:3] + '\x00')[0]
                payload_length = struct.unpack("<I", header[4:7] + '\x00')[0]
                zip_payload = abyte
                while len(zip_payload) < zip_payload_length:
                    chunk = self.sock.recv(zip_payload_length -
                                           len(zip_payload))
                    if len(chunk) == 0:
                        raise errors.InterfaceError(errno=2013)
                    zip_payload = zip_payload + chunk
                if payload_length == 0:
                    self._split_zipped_payload(zip_payload)
                    return self._packet_queue.popleft()
                packets.append(header + zip_payload)
                if payload_length != 16384:
                    break
                header = ''
                abyte = self.sock.recv(1)
                while abyte and len(header) < 7:
                    header += abyte
                    abyte = self.sock.recv(1)
        except IOError as err:
            raise errors.OperationalError(errno=2055,
                                          values=(self.get_address(),
                                                  _strioerror(err)))

        tmp = []
        for packet in packets:
            payload_length = struct.unpack("<I", header[4:7] + '\x00')[0]
            if payload_length == 0:
                tmp.append(packet[7:])
            else:
                tmp.append(zlib.decompress(packet[7:]))

        self._split_zipped_payload(''.join(tmp))
        del tmp

        try:
            return self._packet_queue.popleft()
        except IndexError:
            pass
Пример #10
0
 def send_plain(self, buf, packet_number=None):
     """Send packets to the MySQL server"""
     if packet_number is None:
         self.next_packet_number
     else:
         self._packet_number = packet_number
     packets = _prepare_packets(buf, self._packet_number)
     for packet in packets:
         try:
             self.sock.sendall(packet)
         except Exception, err:
             raise errors.OperationalError(str(err))
Пример #11
0
def get_pool_conn_implicitly(_db_config):
    config = _db_config
    if 'pool' not in config:
        pool = None
    else:
        pool = config['pool']
        if 'use' not in pool:
            raise errors.OperationalError(
                "MySQL pool config error must pool key use")
        if 'size' not in pool:
            raise errors.OperationalError(
                "MySQL pool config error must pool key size")
        if 'name' not in pool:
            raise errors.OperationalError(
                "MySQL pool config error must pool key name")

    if pool and pool['use']:
        conn = PyMysqlPool.mysql.connector.connect(
            pool_name=pool['name'],
            pool_size=pool['size'],
            host=config['host'],
            port=config.get('port', 3306),
            user=config['user'],
            passwd=config['password'],
            db=config['database'],
            charset=config.get('charset', 'utf8'),
            use_unicode=True,
            connect_timeout=1000)
        conn.set_converter_class(FuzzyMySQLConverter)
    else:
        conn = MySQLdb.connect(host=config['host'],
                               port=config.get('port', 3306),
                               user=config['user'],
                               passwd=config['password'],
                               db=config['database'],
                               charset=config.get('charset', 'utf8'),
                               use_unicode=True)
    return conn
Пример #12
0
def _handle_load_data_infile(self, filename):
    try:
        if "~" in filename:
            filename = str(filename).replace("~", os.path.expanduser('~'))
        data_file = open(filename, 'rb')
    except IOError:
        try:
            self._socket.send(b'')
        except AttributeError:
            raise errors.OperationalError("MySQL Connection not available.")
        raise errors.InterfaceError(
            "File '{0}' could not be read".format(filename))

    return self._handle_ok(self._send_data(data_file, send_empty_packet=True))
Пример #13
0
    def _handle_load_data_infile(self, filename):
        """Handle a LOAD DATA INFILE LOCAL request"""
        try:
            data_file = open(filename, 'rb')
        except IOError:
            # Send a empty packet to cancel the operation
            try:

                self._socket.send(b'')
            except AttributeError:
                raise errors.OperationalError(
                    "MySQL Connection not available.")
            raise errors.InterfaceError(
                "File '{0}' could not be read".format(filename))

        return self._handle_ok(self._send_data(data_file,
                                               send_empty_packet=True))
    def open_connection(self):
        """Open the TCP/IP connection to the MySQL server
        """
        # Get address information
        addrinfo = [None] * 5
        try:
            addrinfos = socket.getaddrinfo(self.server_host, self.server_port,
                                           0, socket.SOCK_STREAM,
                                           socket.SOL_TCP)
            # If multiple results we favor IPv4, unless IPv6 was forced.
            for info in addrinfos:
                if self.force_ipv6 and info[0] == socket.AF_INET6:
                    addrinfo = info
                    break
                elif info[0] == socket.AF_INET:
                    addrinfo = info
                    break
            if self.force_ipv6 and addrinfo[0] is None:
                raise errors.InterfaceError(
                    "No IPv6 address found for {0}".format(self.server_host))
            if addrinfo[0] is None:
                addrinfo = addrinfos[0]
        except IOError as err:
            raise errors.InterfaceError(errno=2003,
                                        values=(self.get_address(),
                                                _strioerror(err)))
        else:
            (self._family, socktype, proto, _, sockaddr) = addrinfo

        # Instanciate the socket and connect
        try:
            self._reader, self._writer = (yield from (asyncio.wait_for(
                asyncio.open_connection(self.server_host,
                                        port=self.server_port,
                                        loop=self._loop,
                                        limit=self._default_buffer_limit),
                timeout=self._connection_timeout,
                loop=self._loop)))
        except IOError as err:
            raise errors.InterfaceError(errno=2003,
                                        values=(self.get_address(),
                                                _strioerror(err)))
        except Exception as err:
            raise errors.OperationalError(str(err))
Пример #15
0
    def open_connection(self):
        """Open the TCP/IP connection to the MySQL server
        """
        # Get address information
        addrinfo = None
        try:
            addrinfos = socket.getaddrinfo(self.server_host, self.server_port,
                                           0, 0, socket.SOL_TCP)
            # If multiple results we favor IPv4, unless IPv6 was forced.
            for info in addrinfos:
                if self.force_ipv6 and info[0] == socket.AF_INET6:
                    addrinfo = info
                    break
                elif info[0] == socket.AF_INET:
                    addrinfo = info
                    break
            if self.force_ipv6 and not addrinfo:
                raise errors.InterfaceError(
                    "No IPv6 address found for {0}".format(self.server_host))
            if not addrinfo:
                addrinfo = addrinfos[0]
        except IOError as err:
            raise errors.InterfaceError(errno=2003,
                                        values=(self.get_address(),
                                                _strioerror(err)))

        (self._family, socktype, proto, canonname, sockaddr) = addrinfo

        # Instanciate the socket and connect
        try:
            self.sock = socket.socket(self._family, socktype, proto)
            self.sock.settimeout(self._connection_timeout)
            self.sock.connect(sockaddr)
        except IOError as err:
            raise errors.InterfaceError(errno=2003,
                                        values=(self.get_address(),
                                                _strioerror(err)))
        except Exception as err:
            raise errors.OperationalError(str(err))
Пример #16
0
    def reset_session(self, user_variables=None, session_variables=None):
        """Clears the current active session

        This method resets the session state, if the MySQL server is 5.7.3
        or later active session will be reset without re-authenticating.
        For other server versions session will be reset by re-authenticating.

        It is possible to provide a sequence of variables and their values to
        be set after clearing the session. This is possible for both user
        defined variables and session variables.
        This method takes two arguments user_variables and session_variables
        which are dictionaries.

        Raises OperationalError if not connected, InternalError if there are
        unread results and InterfaceError on errors.
        """
        cn = yield from self.is_connected()
        if not cn:
            raise errors.OperationalError("MySQL Connection not available.")

        try:
            yield from self.cmd_reset_connection()
        except errors.NotSupportedError:
            if self._compress:
                raise errors.NotSupportedError(
                    "Reset session is not supported with compression for "
                    "MySQL server version 5.7.2 or earlier.")
            else:
                yield from self.cmd_change_user(self._user, self._password,
                                     self._database, self._charset_id)

        cur = yield from self.cursor()
        if user_variables:
            for key, value in user_variables.items():
                yield from cur.execute("SET @`{0}` = %s".format(key), (value,))
        if session_variables:
            for key, value in session_variables.items():
                yield from cur.execute("SET SESSION `{0}` = %s".format(key), (value,))
Пример #17
0
    def cursor(self, buffered=None, raw=None, prepared=None, cursor_class=None,
               dictionary=None, named_tuple=None):
        """Instantiates and returns a cursor

        By default, MySQLCursor is returned. Depending on the options
        while connecting, a buffered and/or raw cursor is instantiated
        instead. Also depending upon the cursor options, rows can be
        returned as dictionary or named tuple.

        Dictionary and namedtuple based cursors are available with buffered
        output but not raw.

        It is possible to also give a custom cursor through the
        cursor_class parameter, but it needs to be a subclass of
        mysql.connector.cursor.CursorBase.

        Raises ProgrammingError when cursor_class is not a subclass of
        CursorBase. Raises ValueError when cursor is not available.

        Returns a cursor-object
        """
        if self._unread_result is True:
            raise errors.InternalError("Unread result found.")
        connected = yield from self.is_connected()
        if not connected:
            raise errors.OperationalError("MySQL Connection not available.")
        if cursor_class is not None:
            if not issubclass(cursor_class, CursorBase):
                raise errors.ProgrammingError(
                    "Cursor class needs be to subclass of cursor.CursorBase")
            return (cursor_class)(self)

        buffered = buffered or self._buffered
        raw = raw or self._raw

        cursor_type = 0
        if buffered is True:
            cursor_type |= 1
        if raw is True:
            cursor_type |= 2
        if dictionary is True:
            cursor_type |= 4
        if named_tuple is True:
            cursor_type |= 8
        if prepared is True:
            cursor_type |= 16

        types = {
            0: AioMySQLCursor,  # 0
            1: AioMySQLCursorBuffered,
            2: AioMySQLCursorRaw,
            3: AioMySQLCursorBufferedRaw,
            4: AioMySQLCursorDict,
            5: AioMySQLCursorBufferedDict,
            8: AioMySQLCursorNamedTuple,
            9: AioMySQLCursorBufferedNamedTuple,
            16: AioMySQLCursorPrepared
        }
        try:
            return (types[cursor_type])(self)
        except KeyError:
            args = ('buffered', 'raw', 'dictionary', 'named_tuple', 'prepared')
            raise ValueError('Cursor not available with given criteria: ' +
                             ', '.join([args[i] for i in range(5)
                                        if cursor_type & (1 << i) != 0]))