Exemplo n.º 1
0
    def query(self,
              query,
              data=None,
              fmt='PrettyCompact',
              stream=False,
              verbose=False,
              query_id=None,
              compress=False,
              **kwargs):
        if query.lstrip()[:6].upper().startswith('INSERT'):
            query_split = query.split()
        else:
            query = sqlparse.format(query, strip_comments=True).rstrip(';')

            if verbose and self.cli_settings.get('show_formatted_query'):
                # Highlight & reformat the SQL query
                formatted_query = sqlparse.format(
                    query,
                    reindent_aligned=True,
                    indent_width=2,
                    # keyword_case='upper'  # works poorly in a few cases
                )

                formatter = TerminalFormatter()

                if self.cli_settings.get(
                        'highlight') and self.cli_settings.get(
                            'highlight_truecolor'):
                    formatter = TerminalTrueColorFormatter(
                        style=CHPygmentsStyle)

                print(
                    '\n' +
                    pygments.highlight(formatted_query, CHLexer(), formatter))

            # TODO: use sqlparse's parser instead
            query_split = query.split()

            if not query_split:
                return Response(query, fmt)

            # Since sessions aren't supported over HTTP, we have to make some quirks:
            # USE database;
            if query_split[0].upper() == 'USE' and len(query_split) == 2:
                old_database = self.database
                self.database = query_split[1]
                try:
                    self.test_query()
                except DBException as e:
                    self.database = old_database
                    raise e

                return Response(
                    query,
                    fmt,
                    message='Changed the current database to {0}.'.format(
                        self.database))

            # Set response format
            if query_split[0].upper(
            ) in FORMATTABLE_QUERIES and len(query_split) >= 2:
                if query_split[-2].upper() == 'FORMAT':
                    fmt = query_split[-1]
                elif query_split[-2].upper() != 'FORMAT':
                    if query_split[0].upper() != 'INSERT' or data is not None:

                        if query[-2:] in (r'\g', r'\G'):
                            query = query[:-2] + ' FORMAT Vertical'
                        else:
                            query = query + ' FORMAT {fmt}'.format(fmt=fmt)

        params = {
            'database': self.database,
            'stacktrace': int(self.stacktrace)
        }
        if query_id:
            params['query_id'] = query_id

        has_outfile = False
        if query_split[0].upper() == 'SELECT':
            # Detect INTO OUTFILE at the end of the query
            t_query = [
                t.value.upper() if t.ttype == Keyword else t.value
                for t in sqlparse.parse(query)[0]
                if t.ttype not in (Whitespace, Newline)
            ]

            try:
                last_tokens = t_query[-5:]
                into_pos = last_tokens.index('INTO')
                has_outfile = into_pos >= 0 and last_tokens.index(
                    'OUTFILE') == into_pos + 1

                if has_outfile:
                    path = last_tokens[into_pos + 2].strip("'")
                    # Remove `INTO OUTFILE '/path/to/file.out'`
                    last_tokens.pop(into_pos)
                    last_tokens.pop(into_pos)
                    last_tokens.pop(into_pos)
                    query = ' '.join(t_query[:-5] + last_tokens)
            except ValueError:
                has_outfile = False

        method = 'POST'
        response = self._query(method,
                               query,
                               params,
                               fmt=fmt,
                               stream=stream,
                               data=data,
                               compress=compress,
                               **kwargs)

        if has_outfile:
            try:
                with open(path, 'wb') as f:
                    if not f:
                        return response

                    if stream:
                        for line in response.iter_lines():
                            f.write(line)
                    else:
                        f.write(response.data.encode())
            except Exception as e:
                echo.warning(
                    "Caught an exception when writing to file: {0}".format(e))

        return response
Exemplo n.º 2
0
    def query(self, query, data=None, fmt='PrettyCompactMonoBlock', stream=False, verbose=False, query_id=None, **kwargs):
        query = sqlparse.format(query, strip_comments=True).rstrip(';')

        if kwargs.pop('show_formatted', False) and verbose:
            # Highlight & reformat the SQL query
            formatted_query = sqlparse.format(
                query,
                reindent=True,
                indent_width=4,
                # keyword_case='upper'  # works poorly in a few cases
            )

            print('\n' + pygments.highlight(
                formatted_query,
                CHLexer(),
                TerminalTrueColorFormatter(style=CHPygmentsStyle)
            ))

        # TODO: use sqlparse's parser instead
        query_split = query.split()

        if len(query_split) == 0:
            return Response(query, fmt)

        # Since sessions aren't supported over HTTP, we have to make some quirks:
        # USE database;
        if query_split[0].upper() == 'USE' and len(query_split) == 2:
            old_database = self.database
            self.database = query_split[1]
            try:
                self.test_query()
            except DBException as e:
                self.database = old_database
                raise e

            return Response(query, fmt, message='Changed the current database to {0}.'.format(self.database))

        # SET foo = bar;
        if query_split[0].upper() == 'SET' and len(query_split) == 4:
            key, value = query_split[1], query_split[3]
            old_value = self.settings.get(key)
            self.settings[key] = value
            try:
                self.test_query()
            except DBException as e:
                if old_value is not None:
                    self.settings[key] = old_value
                else:
                    del self.settings[key]
                raise e

            return Response(query, fmt, response='', message='Set {0} to {1}.'.format(key, value))

        # Set response format
        if query_split[0].upper() in FORMATTABLE_QUERIES and len(query_split) >= 2:
            if query_split[-2].upper() == 'FORMAT':
                fmt = query_split[-1]
            elif query_split[-2].upper() != 'FORMAT':
                if query_split[0].upper() != 'INSERT' or data is not None:
                    if query.endswith('\G') or query.endswith('\g'):
                        query = query[:-2] + ' FORMAT Vertical'
                    else:
                        query = query + ' FORMAT {fmt}'.format(fmt=fmt)

        params = {'database': self.database, 'stacktrace': int(self.stacktrace)}
        if query_id:
            params['query_id'] = query_id

        params.update(self.settings)

        # Detect INTO OUTFILE at the end of the query
        t_query = [
            t.value.upper() if t.ttype == Keyword else t.value
            for t in sqlparse.parse(query)[0]
            if t.ttype not in (Whitespace, Newline)
        ]

        try:
            last_tokens = t_query[-5:]
            into_pos = last_tokens.index('INTO')
            has_outfile = into_pos >= 0 and last_tokens.index('OUTFILE') == into_pos + 1

            if has_outfile:
                path = last_tokens[into_pos + 2].strip("'")
                # Remove `INTO OUTFILE '/path/to/file.out'`
                last_tokens.pop(into_pos)
                last_tokens.pop(into_pos)
                last_tokens.pop(into_pos)
                query = ' '.join(t_query[:-5] + last_tokens)
        except ValueError:
            has_outfile = False

        if data is not None:
            data = ''.join(data)

        response = self._query(query, params, fmt=fmt, stream=stream, data=data, **kwargs)

        if has_outfile:
            try:
                with open(path, 'wb') as f:
                    if not f:
                        return response

                    if stream:
                        for line in response.data:
                            f.write(line)
                            f.write(b'\n')
                    else:
                        f.write(response.data.encode())
            except Exception as e:
                echo.warning("Caught an exception when writing to file: {0}".format(e))

        return response