async def _login(self, iteration=0): """Reads challenge from line, generate response and check if everything is okay""" challenge = await self._getblock() response = self._challenge_response(challenge) await self._putblock(response) prompt = await self._getblock() prompt = prompt.strip() if len(prompt) == 0: # Empty response, server is happy pass elif prompt == MSG_OK: pass elif prompt.startswith(MSG_INFO): logger.info("%s" % prompt[1:]) elif prompt.startswith(MSG_ERROR): logger.error(prompt[1:]) raise DatabaseError(prompt[1:]) elif prompt.startswith(MSG_REDIRECT): # a redirect can contain multiple redirects, for now we only use # the first redirect = prompt.split()[0][1:].split(":") if redirect[1] == "merovingian": logger.debug("restarting authentication") if iteration <= 10: await self._login(iteration=iteration + 1) else: raise OperationalError("maximal number of redirects " "reached (10)") elif redirect[1] == "monetdb": self.hostname = redirect[2][2:] self.port, self.database = redirect[3].split("/") self.port = int(self.port) logger.info("redirect to monetdb://%s:%s/%s" % (self.hostname, self.port, self.database)) self.writer.close() await self.writer.wait_closed() self.connect( hostname=self.hostname, port=self.port, username=self.username, password=self.password, database=self.database, language=self.language, ) else: raise ProgrammingError("unknown redirect: %s" % prompt) else: raise ProgrammingError("unknown state: %s" % prompt)
def convert(data): """ Return the appropriate convertion function based upon the python type. """ if type(data) in mapping_dict: return mapping_dict[type(data)](data) else: for type_, func in mapping: if issubclass(type(data), type_): return func(data) raise ProgrammingError("type %s not supported as value" % type(data))
def convert(data, type_code): """ Calls the appropriate convertion function based upon the python type """ # null values should always be replaced by None type if data == "nil": return None try: return mapping[type_code](data) except KeyError: raise ProgrammingError("type %s is not supported" % type_code)
def _extract_timezone(data): sign_symbol = data[-6] if sign_symbol == '+': sign = 1 elif sign_symbol == '-': sign = -1 else: raise ProgrammingError("no + or - in %s" % data) return data[:-6], datetime.timedelta(hours=sign * int(data[-5:-3]), minutes=sign * int(data[-2:]))
async def cmd(self, operation): """ put a mapi command on the line""" logger.debug("executing command %s" % operation) if self.state != STATE_READY: raise (ProgrammingError, "Not connected") if not bool(re.match("create|drop", operation, re.I)): await self._putblock(operation) response = await self._getblock() else: await lock.acquire() try: await self._putblock(operation) response = await self._getblock() finally: lock.release() if not len(response): return "" elif response.startswith(MSG_OK): return response[3:].strip() or "" if response == MSG_MORE: # tell server it isn't going to get more return self.cmd("") # print(operation+": "+response) # If we are performing an update test for errors such as a failed # transaction. # We are splitting the response into lines and checking each one if it # starts with MSG_ERROR. If this is the case, find which line records # the error and use it to call handle_error. if response[:2] == MSG_QUPDATE: lines = response.split("\n") if any([l.startswith(MSG_ERROR) for l in lines]): index = next(i for i, v in enumerate(lines) if v.startswith(MSG_ERROR)) exception, msg = handle_error(lines[index][1:]) raise exception('\n'.join(lines)) if response[0] in [MSG_Q, MSG_HEADER, MSG_TUPLE]: return response elif response[0] == MSG_ERROR: exception, msg = handle_error(response[1:]) raise exception(msg) elif response[0] == MSG_INFO: logger.info("%s" % (response[1:])) elif self.language == "control" and not self.hostname: if response.startswith("OK"): return response[2:].strip() or "" else: return response else: raise ProgrammingError("unknown state: %s" % response)
def read_response(self): response = self._getblock() if not len(response): return "" if response.startswith(MSG_OK): return response[3:].strip() or "" if response == MSG_MORE: # tell server it isn't going to get more return self.cmd("") # If we are performing an update test for errors such as a failed # transaction. # We are splitting the response into lines and checking each one if it # starts with MSG_ERROR. If this is the case, find which line records # the error and use it to call handle_error. if response[:2] == MSG_QUPDATE: lines = response.split(b'\n') if any([l.startswith(MSG_ERROR) for l in lines]): index = next(i for i, v in enumerate(lines) if v.startswith(MSG_ERROR)) exception, string = handle_error(lines[index][1:]) raise exception(string) if response[0:1] in [ MSG_Q, MSG_HEADER, MSG_TUPLE, MSG_NEW_RESULT_HEADER, MSG_INITIAL_RESULT_CHUNK, MSG_RESULT_CHUNK ]: return response elif response[0:1] == MSG_ERROR: exception, string = handle_error(response[1:]) raise exception(string) elif response[0:1] == MSG_INFO: logger.info("%s" % (response[1:])) elif self.language == 'control' and not self.hostname: if response.startswith("OK"): return response[2:].strip() or "" else: return response else: raise ProgrammingError("unknown state: %s" % response)
def _command(self, operation): if self._mapi.state != mapi.STATE_READY: raise ProgrammingError("Not connected") self._mapi._putblock(operation)