def _handle_ok(self, packet):
        '''
        ************************************************************
            Function    : _handle_ok
            Arguments   : packet (string) : need handle packet
            Return      : dict
            Description : Handle ok packet.
        ************************************************************
        '''
        if self._protocol.is_ok(packet):
            GBASELOGGER.debug('Parse ok packet.')
            ok_packet = self._protocol.parse_ok_res(packet)

            GBASELOGGER.debug('Get server status from packet.')
            flag = ok_packet['server_status']

            GBASELOGGER.debug('Trigger next result.')
            self._trigger_next_result(flag)
            return ok_packet
        elif self._protocol.is_error(packet):
            GBASELOGGER.error("No receive ok packet or package is error.")
            raise GBaseError.InterfaceError(
                "No receive ok packet or package is error.")

        GBASELOGGER.error('Packet is not OK packet')
        raise GBaseError.InterfaceError('Packet is not OK packet')
    def _send(self, command, argument=None):
        '''
        ************************************************************
            Function    : _handle_result
            Arguments   : 1) command (int)     : SQL command flag. ServerCmd.QUERY
                          2) argument (string) : SQL command. Select 1
            Return      : packets (string)
            Description : Send a command to the GBase server
        ************************************************************
        '''
        GBASELOGGER.debug("Send packet. command='%s', argument='%s'" %
                          (command, argument))
        if self.unread_result:
            GBASELOGGER.error("Unread result found.")
            raise GBaseError.InternalError("Unread result found.")

        try:
            GBASELOGGER.debug("Make command.")
            packet = self._protocol.make_command(command, argument)
            GBASELOGGER.debug("Send packet.")
            self._socket.send_data(packet, 0)
        except AttributeError:
            GBASELOGGER.error("GBase Connection not available.")
            raise GBaseError.InternalError("GBase Connection not available.")

        GBASELOGGER.debug("Receive packet.")
        packet = self._socket.receive_packet()
        GBASELOGGER.debug("Return receive packet.")
        return packet
    def _handle_eof(self, packet):
        '''
        ************************************************************
            Function    : _handle_eof
            Arguments   : packet (string) : need handle packet
            Return      : list
            Description : Handle a GBase EOF packet
        ************************************************************
        '''
        if self._protocol.is_eof(packet):
            GBASELOGGER.debug('Parse EOF packet.')
            eof_packet = self._protocol.parse_eof(packet)

            GBASELOGGER.debug('Get status flag.')
            server_flag = eof_packet['server_flag']

            GBASELOGGER.debug('Trigger next result.')
            self._trigger_next_result(server_flag)
            return eof_packet
        elif self._protocol.is_error(packet):
            res = self._protocol.parse_error_res(packet)
            GBASELOGGER.error(
                "Packet is error. Errno=%s ErrMsg=%s SqlState=%s" %
                (res['errno'], res['errmsg'], res['sqlstate']))
            raise GBaseError.get_gbase_exception(res)

        GBASELOGGER.error('Expected EOF packet')
        raise GBaseError.InterfaceError('Expected EOF packet')
    def _do_authcheck(self):
        '''
        ************************************************************
            Function    : _do_authcheck
            Arguments   : 
            Return      : bool
            Description : Send authorize check packet (user, pass)
        ************************************************************
        '''
        # make auth packet
        try:
            GBASELOGGER.debug('Make auth packet.')
            packet = self._protocol.make_auth(self._user, self._password,
                                              self._hello_res['scramble'],
                                              self._database, self._charset_id,
                                              self._client_flags)
        except:
            GBASELOGGER.error('Make auth packet exception.')
            raise GBaseError.InterfaceError('Make auth packet exception.')

        # send auth package
        try:
            GBASELOGGER.debug("Send auth packet.")
            self._socket.send_data(packet)
        except:
            GBASELOGGER.error('Send auth packet exception.')
            raise GBaseError.InterfaceError('Send auth packet exception.')

        # receive server packet
        try:
            GBASELOGGER.debug("Receive auth packet.")
            packet = self._socket.receive_packet()
        except:
            GBASELOGGER.error('Receive packet exception.')
            raise GBaseError.InterfaceError('Receive packet exception.')

        # judgement eof packet
        if self._protocol.is_eof(packet):
            raise GBaseError.NotSupportedError(
                "Old passwords mode is not supported.")

        if self._protocol.is_error(packet):
            res = self._protocol.parse_error_res(packet)
            GBASELOGGER.error(
                "Packet is error. Errno=%s ErrMsg=%s SqlState=%s" %
                (res['errno'], res['errmsg'], res['sqlstate']))
            raise GBaseError.get_gbase_exception(res)

        try:
            if (not (self._client_flags & ClientFlag.CONNECT_WITH_DB)
                    and self._database):
                GBASELOGGER.debug('Initial database.')
                self.initdb(self._database)
        except:
            GBASELOGGER.error('Initial database exception.')
            raise

        return True
    def _handle_result(self, packet):
        '''
        ************************************************************
            Function    : _handle_result
            Arguments   : packet (string) : need handle packet
            Return      : dict
            Description : Get a GBase Result
        ************************************************************
        '''
        if not packet or len(packet) < 4:
            GBASELOGGER.error('GBase Server can not response')
            raise GBaseError.InterfaceError('GBase Server can not response')
        elif self._protocol.is_ok(packet):
            GBASELOGGER.debug("Packet is OK.")
            return self._handle_ok(packet)
        elif self._protocol.is_eof(packet):
            GBASELOGGER.error("Packet is EOF.")
            return self._handle_eof(packet)
        elif self._protocol.is_error(packet):
            res = self._protocol.parse_error_res(packet)
            GBASELOGGER.error(
                "Packet is error. Errno=%s ErrMsg=%s SqlState=%s" %
                (res['errno'], res['errmsg'], res['sqlstate']))
            raise GBaseError.get_gbase_exception(res)

        # We have a text result set
        GBASELOGGER.debug('Parse column count.')
        column_count = self._protocol.parse_column_count(packet)
        if not column_count or not isinstance(column_count, int):
            GBASELOGGER.error('Result set is not valid.')
            raise GBaseError.InterfaceError('Result set is not valid.')

        GBASELOGGER.debug("Loop receive column. count:'%s'" % column_count)
        columns = [
            None,
        ] * column_count
        for i in xrange(0, column_count):
            packet = self._socket.receive_packet()
            GBASELOGGER.debug("Receive column packet and parse packet.")
            columns[i] = self._protocol.parse_column_res(packet)

        GBASELOGGER.debug("Recive EOF packet.")
        packet = self._socket.receive_packet()
        GBASELOGGER.debug("Handle EOF packet.")
        eof_packet = self._handle_eof(packet)

        GBASELOGGER.debug("Set unread_result=True.")
        self.unread_result = True
        return {'columns': columns, 'eof': eof_packet}
    def reconnect(self, attempts=1, delay=0):
        '''
        ************************************************************
            Function    : ping
            Arguments   : 1) attempts (int): Try count
                          2) delay (int): Delay time when try re-connect
            Return      : 
            Description : Attempt to reconnect to the GBase server. 
                          Default only try once. 
        ************************************************************
        '''
        counter = 0
        while counter != attempts:
            counter = counter + 1
            try:
                GBASELOGGER.debug("Disconnect to GBase server.")
                self.disconnect()

                GBASELOGGER.debug("Connect to GBase server.")
                self.connect()
            except Exception, err:
                if counter == attempts:
                    GBASELOGGER.error("Can not reconnect to GBase after %s "
                                      "attempt(%s): " % (attempts, err))
                    raise GBaseError.InterfaceError(
                        "Can not reconnect to GBase after %s "
                        "attempt(%s): " % (attempts, err))
            if delay > 0:
                time.sleep(delay)
    def _open_connection(self):
        '''
        ************************************************************
            Function    : _open_connection
            Arguments   : 
            Return      : 
            Description : Use socket object open connection and make auth check
                          1) receive hello packet (shake hands)
                          2) auth check (user, pass)
                          3) set character
                          4) set auto commit
        ************************************************************
        '''
        # open socket
        GBASELOGGER.debug('Get socket object.')
        self._socket = self._get_connection()

        # hand shake
        GBASELOGGER.debug('Shake hand and send hello packet.')
        self._do_hello()

        # auth check
        GBASELOGGER.debug('Authorize and check user password.')
        if self._do_authcheck():
            # set charset
            GBASELOGGER.debug('Set character set and collation.')
            self.set_charset_collation(charset=self._charset_id)

            GBASELOGGER.debug("Set other initial info. Include "
                              "autocommit, time_zone, sql_mode, etc.")
            self._do_setotherinfo()
        else:
            GBASELOGGER.error('Authorize failure.')
            raise GBaseError.InternalError('Authorize failure.')
    def _do_hello(self):
        '''
        ************************************************************
            Function    : _do_hello
            Arguments   : 
            Return      : 
            Description : Receive hello packet (shake hands).
                          Will receive to hello packet when first 
                          connect to GBase server
        ************************************************************
        '''
        try:
            GBASELOGGER.debug('Receive hello package.')
            packet = self._socket.receive_packet()
        except:
            GBASELOGGER.error("Receive packet exception")
            raise GBaseError.InterfaceError("Receive packet exception.")

        if self._protocol.is_error(packet):
            res = self._protocol.parse_error_res(packet)
            GBASELOGGER.error(
                "Packet is error. Errno=%s ErrMsg=%s SqlState=%s" %
                (res['errno'], res['errmsg'], res['sqlstate']))
            raise GBaseError.get_gbase_exception(res)

        try:
            GBASELOGGER.debug('Parse hello package.')
            hello_res = self._protocol.parse_hello_res(packet)
        except:
            GBASELOGGER.error('Parse hello package error.')
            raise GBaseError.InterfaceError('Parse hello package error.')

        try:
            # get server version from package
            server_version = hello_res['server_version_original']
        except:
            GBASELOGGER.error('Hello package no server_version property.')
            raise GBaseError.InterfaceError(
                'Hello package no server_version property.')

        GBASELOGGER.debug("Get hello package & server_version info "
                          "from hello package. "
                          "hello_res: '%s' server_version: '%s'" %
                          (hello_res, server_version))
        self._hello_res = hello_res
        self._server_version = server_version
    def _exec_query(self, statement):
        '''
        ************************************************************
            Function    : _exec_query
            Arguments   : 1) statement (string) : SQL command
            Return      : 
            Description : Execute a query
        ************************************************************
        '''
        if self.unread_result is True:
            GBASELOGGER.error("Unread result found.")
            raise GBaseError.OperationalError("Unread result found.")

        GBASELOGGER.debug("Execute query. '%s'" % statement)
        self.query(statement)
    def cursor(self):
        '''
        ************************************************************
            Function    : cursor
            Arguments   : 
            Return      : instance of GBaseCursor class
            Description : Returns a cursor object
        ************************************************************
        '''
        if not self.is_connected():
            GBASELOGGER.error("GBase Connection not available.")
            raise GBaseError.OperationalError(
                "GBase Connection not available.")

        GBASELOGGER.debug("Return GBaseCursor object.")
        return GBaseCursor(self)
    def initdb(self, db):
        '''
        ************************************************************
            Function    : initdb
            Arguments   : db(string) : database name
            Return      : dict
            Description : Send initial database packet
        ************************************************************
        '''
        packet = self._send(ServerCmd.INIT_DB, db)

        if self._protocol.is_error(packet):
            res = self._protocol.parse_error_res(packet)
            GBASELOGGER.error(
                "Packet is error. Errno=%s ErrMsg=%s SqlState=%s" %
                (res['errno'], res['errmsg'], res['sqlstate']))
            raise GBaseError.get_gbase_exception(res)

        return self._handle_ok(packet)
    def quit(self):
        '''
        ************************************************************
            Function    : quit
            Arguments   : 
            Return      : string
            Description : Send quit packet to the GBase Server
        ************************************************************
        '''
        if self.unread_result:
            GBASELOGGER.error("Unread result found.")
            raise GBaseError.InternalError("Unread result found.")

        GBASELOGGER.debug("Make command packet.")
        packet = self._protocol.make_command(ServerCmd.QUIT)

        GBASELOGGER.debug("Send command packet.")
        self._socket.send_data(packet, 0)
        return packet
    def query(self, statement):
        '''
        ************************************************************
            Function    : query
            Arguments   : 1) statement (string) : SQL command
            Return      : dict
            Description : Execute a query and return result
        ************************************************************
        '''
        GBASELOGGER.debug("Send query packet. SQL: '%s'" % statement)
        GBASELOGGER.sql(statement)
        packet = self._send(ServerCmd.QUERY, statement)
        GBASELOGGER.debug("Handle result.")
        result = self._handle_result(packet)

        if self._have_next_result:
            GBASELOGGER.sql(
                'Use query_iter for statements with multiple queries.')
            raise GBaseError.OperationalError(
                'Use query_iter for statements with multiple queries.')
        return result
    def get_rows(self, count=None):
        '''
        ************************************************************
            Function    : get_rows
            Arguments   : 1) count (int) : Fetch how much rows
            Return      : a tuple with 2 elements: a list with all rows and
                          the EOF packet.
            Description : Get all rows returned by the GBase server
        ************************************************************
        '''
        if not self.unread_result:
            GBASELOGGER.error("No result set available.")
            raise GBaseError.InternalError("No result set available.")

        GBASELOGGER.debug("Read result set rows.")
        rows = self._protocol.read_result_set(self._socket, count)
        if rows[-1] is not None:
            GBASELOGGER.debug(
                "Trigger next result and set unread_result=False.")
            self._trigger_next_result(rows[-1]['server_flag'])
            self.unread_result = False

        return rows
    def ping(self, reconnect=False, attempts=1, delay=0):
        '''
        ************************************************************
            Function    : ping
            Arguments   : 1) reconnect (bool): Is or not re-connect GBase server
                          2) attempts (int): Try count
                          3) delay (int): Delay time when try re-connect
            Return      : 
            Description : Send ping command to GBase server
        ************************************************************
        '''
        try:
            packet = self._send(ServerCmd.PING)

            GBASELOGGER.debug("Send handle ok command.")
            self._handle_ok(packet)
        except:
            if reconnect:
                GBASELOGGER.debug("Send reconnect to GBase server.")
                self.reconnect(attempts=attempts, delay=delay)
            else:
                GBASELOGGER.error("Connection to GBase is not available.")
                raise GBaseError.InterfaceError(
                    "Connection to GBase is not available.")
    def set_client_flags(self, flags):
        '''
        ************************************************************
            Function    : set_client_flags
            Arguments   : 1) flags (int): client flags value
            Return      : int
            Description : Set the client flags
                          set_client_flags([ClientFlag.FOUND_ROWS,-ClientFlag.LONG_FLAG])
        ************************************************************
        '''
        if isinstance(flags, int) and flags > 0:
            self._client_flags = flags
        elif isinstance(flags, (tuple, list)):
            for flag in flags:
                if flag < 0:
                    self._client_flags &= ~abs(flag)
                else:
                    self._client_flags |= flag
        else:
            GBASELOGGER.error("set_client_flags expect int (>0) or set")
            raise GBaseError.ProgrammingError(
                "set_client_flags expect int (>0) or set")

        return self._client_flags
    def query_iterator(self, statements):
        '''
        ************************************************************
            Function    : query_iterator
            Arguments   : 1) statements (string) : multiple sql string
            Return      : 
            Description : Send one or more statements to the GBase server
        ************************************************************
        '''
        # Handle the first query result
        GBASELOGGER.debug("Handle the first query result '%s'" % statements)
        packet = self._send(ServerCmd.QUERY, statements)
        yield self._handle_result(packet)

        # Handle next results
        while self._have_next_result:
            if self.unread_result:
                GBASELOGGER.error("Unread result found.")
                raise GBaseError.InternalError("Unread result found.")
            else:
                GBASELOGGER.debug("Handle receive packet.")
                packet = self._socket.receive_packet()
                result = self._handle_result(packet)
            yield result
    def parsecfg(self, **kwargs):
        '''
        ************************************************************
            Function    : parsecfg
            Arguments   : 1) **kwargs (dict) : connection arguments
                                                { 'user': gbase,
                                                  'port': 5258  }
            Return      : 
            Description : Parse config arguments and get values.
        ************************************************************
        '''
        config = kwargs.copy()
        # dsn
        if 'dsn' in config:
            GBASELOGGER.error('Not support dsn key word.')
            raise GBaseError.NotSupportedError('Not support dsn key word.')

        # host
        if 'host' in config:
            self._host = config['host']
            del config['host']

        # user
        if 'user' in config:
            self._user = config['user']
            del config['user']

        # Compatible other key
        compatible_keys = [
            ('db', 'database'),
            ('passwd', 'password'),
            ('connect_timeout', 'connection_timeout'),
        ]

        for comp_key, full_key in compatible_keys:
            try:
                if full_key not in config:
                    config[full_key] = config[comp_key]
                del config[comp_key]
            except KeyError:
                pass  # Missing compat argument is OK

        # password
        if 'password' in config:
            self._password = config['password']
            del config['password']

        # port
        if 'port' in config:
            try:
                self._port = int(config['port'])
                del config['port']
            except KeyError:
                pass  # Missing port argument is OK
            except ValueError:
                raise ValueError("TCP/IP port number should be an integer")

        if 'connection_timeout' in config:
            self.connection_timeout = config['connection_timeout']
            del config['connection_timeout']

        if 'autocommit' in config:
            self.autocommit = config['autocommit']
            del config['autocommit']

        if 'sql_mode' in config:
            self.sql_mode = config['sql_mode']
            del config['sql_mode']

        if 'get_warnings' in config:
            self.get_warnings = config['get_warnings']
            del config['get_warnings']

        # Configure client flags
        try:
            default = ClientFlag.get_default()
            self.set_client_flags(config['client_flags'] or default)
            del config['client_flags']
        except KeyError:
            pass  # Missing client_flags-argument is OK

        # Configure character set and collation
        if ('charset' in config or 'collation' in config):
            try:
                self.charset = config['charset']
                del config['charset']
            except KeyError:
                self.charset = None
            try:
                collation = config['collation']
                del config['collation']
            except KeyError:
                collation = None
            self._charset_id = CharacterSet.get_charset_info(
                self.charset, collation)[0]

        if 'raise_on_warnings' in config:
            self.raise_on_warnings = config['raise_on_warnings']
            del config['raise_on_warnings']

        if 'use_unicode' in config:
            self.use_unicode = config["use_unicode"]
            del config['use_unicode']

        # Other configuration
        for k, v in config.items():
            # TRACE Configuration
            if k.startswith('trace'):
                continue

            try:
                self.DEFAULT_CONFIG[k]
            except KeyError:
                raise AttributeError("The argument is not support. '%s'" % k)

            attribute = '_' + k
            try:
                setattr(self, attribute, v.strip())
            except AttributeError:
                setattr(self, attribute, v)