def extract(rcol: monetdbe_column, r: int, text_factory: Optional[Callable[[str], Any]] = None): """ Extracts values from a monetdbe_column. The text_factory is optional, and wraps the value with a custom user supplied text function. """ type_info = monet_c_type_map[rcol.type] col = ffi.cast(f"monetdbe_column_{type_info.c_string_type} *", rcol) if col.is_null(col.data + r): return None else: col_data = col.data[r] if rcol.sql_type.name != ffi.NULL and ffi.string( rcol.sql_type.name).decode() == 'decimal': col_data = Decimal(col_data) / (Decimal(10)** rcol.sql_type.scale) if type_info.py_converter: result = type_info.py_converter(col_data) if rcol.type == lib.monetdbe_str and text_factory: return text_factory(result) return result return col_data
def open(self): if not self.dbdir: url = ffi.NULL else: url = str(self.dbdir).encode() p_connection = ffi.new("monetdbe_database *") p_options = ffi.new("monetdbe_options *") p_options.memorylimit = self.memorylimit p_options.querytimeout = self.querytimeout p_options.sessiontimeout = self.sessiontimeout p_options.nr_threads = self.nr_threads result_code = lib.monetdbe_open(p_connection, url, p_options) connection = p_connection[0] errors = { 0: "OK", -1: "Allocation failed", -2: "Error in DB", } if result_code: if result_code == -2: error = ffi.string(lib.monetdbe_error(connection)).decode() lib.monetdbe_close(connection) else: error = errors.get(result_code, "unknown error") raise exceptions.OperationalError( f"Failed to open database: {error} (code {result_code})") return connection
def check_error(raw: char_p) -> None: """ Raises: exceptions.Error: or subclass in case of error, which exception depends on the error type. """ if not raw: return decoded = ffi.string(raw).decode() _logger.error(decoded) match = error_matcher.match(decoded) if not match: for error_code, other_matcher in other_matchers: other_match = other_matcher.match(decoded) if other_match: exception = errors[error_code] msg = other_match.groups()[0] break else: # the error string is in an unknown format exception = exceptions.DatabaseError msg = decoded else: _, _, code, msg = match.groups() exception = errors.get(code, exceptions.DatabaseError) raise exception(msg)
def get_columns(self, table: str, schema: str = 'sys') -> Iterator[Tuple[str, int]]: count_p = ffi.new('size_t *') names_p = ffi.new('char ***') types_p = ffi.new('int **') lib.monetdbe_get_columns(self._connection, schema.encode(), table.encode(), count_p, names_p, types_p) for i in range(count_p[0]): name = ffi.string(names_p[0][i]).decode() type_ = types_p[0][i] yield name, type_
def get_columns(self, table: str, schema: str = 'sys') -> Iterator[Tuple[str, int]]: self._switch() count_p = ffi.new('size_t*') columns_p = ffi.new('monetdbe_column**') lib.monetdbe_get_columns(self._monetdbe_database, schema.encode(), table.encode(), count_p, columns_p) for i in range(count_p[0]): name = ffi.string(columns_p[0][i].name).decode() type_ = columns_p[0][i].type yield name, type_
def check_error(msg: ffi.CData) -> None: """ Raises: exceptions.Error: or subclass in case of error, which exception depends on the error type. """ if msg: decoded = ffi.string(msg).decode() _logger.error(decoded) match = error_match.match(decoded) if not match: raise exceptions.OperationalError(decoded) _, _, error, msg = match.groups() if error not in errors: ... exception = errors.get(error, exceptions.DatabaseError) raise exception(msg)
def make_blob(blob: ffi.CData) -> str: if blob: return ffi.string(blob.data[0:blob.size]) else: return ""
def make_string(blob: ffi.CData) -> str: if blob: return ffi.string(blob).decode() else: return ""
def make_string(blob: char_p) -> str: if blob: return ffi.string(blob).decode() else: return ""
def version() -> str: return ffi.string(lib.monetdbe_version()).decode()