Example #1
0
    def _execute_python(self,
                        operation: str,
                        parameters: parameters_type = None) -> 'Cursor':
        """
        Execute operation with Python based statement preparation.

        Args:
            operation: the query you want to execute
            parameters: an optional iterable containing arguments for the operation.

        Returns:
            the cursor object itself

        Raises:
            OperationalError: if the execution failed
        """
        self._check_connection()

        self.description = None  # which will be set later in fetchall

        self.connection.cleanup_result()

        splitted = strip_split_and_clean(operation)
        if len(splitted) == 0:
            raise ProgrammingError("Empty query")
        if len(splitted) > 1:
            raise ProgrammingError("Multiple queries in one execute() call")

        formatted = format_query(operation, parameters)
        self.connection.result, self.rowcount = self.connection.query(
            formatted, make_result=True)
        self.connection.total_changes += self.rowcount
        self._set_description()
        return self
Example #2
0
def _format_iterable(cleaned_query: str, parameters: Sequence[Any],
                     query: str):
    # we do this a bit strange to make sure the test_ExecuteParamSequence sqlite test passes
    escaped_list: List[str] = [
        convert(parameters[i]) for i in range(len(parameters))
    ]

    if ':' in cleaned_query:
        x = sub(r':(\w+)', r'{\1}', query)

        # The numbering used starts at 1, while python starts 0, so we insert a bogus prefix
        prefixed = [''] + escaped_list

        return x.format(*prefixed)

    if '?' in cleaned_query:  # qmark style

        if cleaned_query.count('?') != len(escaped_list):
            raise ProgrammingError(
                f"Number of arguments ({len(escaped_list)}) doesn't "
                f"match number of '?' ({cleaned_query.count('?')})")

        return query.replace('?', '{}').format(*escaped_list)
    elif '%s' in cleaned_query:  # pyformat style
        return query % tuple(escaped_list)
    else:
        return cleaned_query
Example #3
0
def format_query(query: str, parameters: parameters_type = None) -> str:
    if type(query) != str:
        raise TypeError

    cleaned_query = remove_quoted_substrings(query)

    if parameters is None:
        for symbol in ':?':
            if symbol in cleaned_query:
                raise ProgrammingError(
                    f"unexpected symbol '{symbol}' in operation")
        return query

    # named, numeric or format style
    if isinstance(parameters, Dict):
        return _format_mapping(cleaned_query, parameters, query)

    # qmark or pyformat style
    elif isinstance(parameters,
                    Sequence) or (isinstance(parameters, Sized)
                                  and hasattr(parameters, '__getitem__')):
        return _format_iterable(cleaned_query, parameters, query)

    else:
        raise ValueError(
            f"parameters '{parameters}' type '{type(parameters)}' not supported"
        )
Example #4
0
    def _check_result(self) -> None:
        """
        Check if an operation has been executed and a result is available.

        Raises:
            ProgrammingError: if no result is available.
        """
        if not self.result:
            raise ProgrammingError("fetching data but no query executed")
Example #5
0
    def _check_connection(self):
        """
        Check if we are attached to the lower level interface

        Raises:
            ProgrammingError: if no lower level interface is attached
        """
        if not hasattr(self, 'connection') or not self.connection:
            raise ProgrammingError(
                "no connection to lower level database available")
Example #6
0
    def commit(self) -> 'Cursor':
        """
        Commit the current pending transaction.

        Returns:
            the current cursor
        """
        if not hasattr(self, 'connection') or not self.connection:
            raise ProgrammingError(
                "no connection to lower level database available")

        self.connection.commit()
        return self
Example #7
0
def _format_mapping(cleaned_query: str, parameters: Dict[str, Any],
                    query: str):
    if '?' in cleaned_query:
        raise ProgrammingError("'?' in formatting with mapping as parameters")

    escaped: Dict[str, str] = {k: convert(v) for k, v in parameters.items()}

    if ':' in cleaned_query:  # qmark
        x = sub(r':(\w+)', r'{\1}', query)
    elif '%' in cleaned_query:
        return query % escaped

    if hasattr(type(parameters), '__missing__'):
        # this is something like a dict with a default value
        try:
            # mypy doesn't understand that this is a dict-like with a default __missing__ value
            return DefaultFormatter(parameters).format(x, **escaped)
        except KeyError as e:
            raise ProgrammingError(e)
    try:
        return x.format(**escaped)
    except KeyError as e:
        raise ProgrammingError(e)
Example #8
0
    def execute(self,
                operation: str,
                parameters: Optional[Iterable] = None) -> 'Cursor':
        """
        Execute operation

        Args:
            operation: the query you want to execute
            parameters: an optional iterable containing arguments for the operation.

        Returns:
            the cursor object itself

        Raises:
            OperationalError: if the execution failed
        """
        self._check_connection()
        self.description = None  # which will be set later in fetchall
        self._fetch_generator = None

        if self.result:
            self.connection.lowlevel.cleanup_result(
                self.result)  # type: ignore
            self.result = None

        splitted = strip_split_and_clean(operation)
        if len(splitted) == 0:
            raise ProgrammingError("Empty query")
        if len(splitted) > 1:
            raise ProgrammingError("Multiple queries in one execute() call")

        formatted = format_query(operation, parameters)
        self.result, self.rowcount = self.connection.lowlevel.query(
            formatted, make_result=True)  # type: ignore
        self.connection.total_changes += self.rowcount
        self._set_description()
        return self
Example #9
0
def numpy_monetdb_map(numpy_type: np.dtype):
    if numpy_type.kind == 'U':
        # this is an odd one, the numpy type string includes the width. Also, we don't format
        # monetdb string columns as fixed width numpy columns yet, so technically this type is
        # non-reversable for now.
        return MonetdbTypeInfo(lib.monetdbe_str, "string", numpy_type,
                               "char *", None)
    if numpy_type.kind == 'M':
        # TODO: another odd one
        return MonetdbTypeInfo(lib.monetdbe_timestamp, "timestamp",
                               np.dtype(np.datetime64), "int64_t", None)

    if numpy_type.kind in supported_numpy_types:  # type: ignore
        return numpy_type_map[numpy_type]
    raise ProgrammingError(
        f"append() called with unsupported type {numpy_type}")
Example #10
0
    def executemany(
            self, operation: str,
            seq_of_parameters: Union[Iterator,
                                     Iterable[Iterable]]) -> 'Cursor':
        """
        Prepare a database operation (query or command) and then execute it against all parameter sequences or
        mappings found in the sequence seq_of_parameters.

        Args:
            operation: the SQL query to execute
            seq_of_parameters: An optional iterator or iterable containing an iterable of arguments
        """
        self._check_connection()
        self.description = None  # which will be set later in fetchall

        if self.result:
            self.connection.lowlevel.cleanup_result(
                self.result)  # type: ignore
            self.result = None

        total_affected_rows = 0

        if operation[:6].lower().strip() == 'select':
            raise ProgrammingError(
                "Don't use a SELECT statement with executemany()")

        if hasattr(seq_of_parameters, '__iter__'):
            iterator = iter(seq_of_parameters)
        else:
            iterator = seq_of_parameters  # type: ignore   # mypy gets confused here

        while True:
            try:
                parameters = next(iterator)
            except StopIteration:
                break

            formatted = format_query(operation, parameters)
            self.result, affected_rows = self.connection.lowlevel.query(
                formatted, make_result=True)  # type: ignore
            total_affected_rows += affected_rows

        self.rowcount = total_affected_rows
        self.connection.total_changes += total_affected_rows
        self._set_description()
        return self
Example #11
0
def format_query(
    query: str,  # type: ignore
    parameters: Optional[Union[Iterable[str], Dict[str, Any], Sized]] = None
) -> str:  # type: ignore
    if type(query) != str:
        raise TypeError

    cleaned_query = remove_quoted_substrings(query)

    if parameters is not None:
        # named, numeric or format style
        if hasattr(type(parameters), '__getitem__') and hasattr(type(parameters), 'keys') \
                and hasattr(type(parameters), 'items'):

            if '?' in cleaned_query:
                raise ProgrammingError(
                    "'?' in formatting with mapping as parameters")

            escaped: Dict[str, str] = {
                k: convert(v)
                for k, v in parameters.items()
            }  # type: ignore

            if ':' in cleaned_query:  # qmark
                x = sub(r':(\w+)', r'{\1}', query)
            elif '%' in cleaned_query:  # pyformat
                return query % escaped

            if hasattr(type(parameters), '__missing__'):
                # this is something like a dict with a default value
                try:
                    # mypy doesn't understand that this is a dict-like with a default __missing__ value
                    return DefaultFormatter(parameters).format(
                        x, **escaped)  # type: ignore
                except KeyError as e:
                    raise ProgrammingError(e)
            try:
                return x.format(**escaped)
            except KeyError as e:
                raise ProgrammingError(e)

        # qmark or pyformat style
        elif hasattr(type(parameters), '__iter__') \
                or (hasattr(type(parameters), '__len__') and hasattr(type(parameters), '__getitem__')):

            # todo (gijs): check typing
            # we do this a bit strange to make sure the test_ExecuteParamSequence sqlite test passes
            escaped_list: List[Optional[str]] = [
                convert(parameters[i]) for i in range(len(parameters))
            ]  # type: ignore

            if ':' in cleaned_query:
                # raise ProgrammingError("':' in formatting with named style parameters")
                x = sub(r':(\w+)', r'{\1}', query)

                # off by one error
                # todo (gijs): check typing
                prefixed = [None] + escaped_list  # type: ignore

                return x.format(*prefixed)

            if '?' in cleaned_query:  # named style

                if cleaned_query.count('?') != len(escaped_list):
                    raise ProgrammingError(
                        f"Number of arguments ({len(escaped_list)}) doesn't "
                        f"match number of '?' ({cleaned_query.count('?')})")

                return query.replace('?', '{}').format(*escaped_list)
            elif '%s' in cleaned_query:  # pyformat style
                return query % tuple(escaped_list)
            else:
                return cleaned_query
        else:
            raise ValueError(
                f"parameters '{parameters}' type '{type(parameters)}' not supported"
            )
    else:
        for symbol in ':?':
            if symbol in cleaned_query:
                raise ProgrammingError(
                    f"unexpected symbol '{symbol}' in operation")
        return query
def numpy_monetdb_map(numpy_type: np.dtype):
    if numpy_type.kind in ('i', 'f'):  # type: ignore
        return numpy_type_map[numpy_type]
    raise ProgrammingError("append() only support int and float family types")