1
0
Fork 0

Merging upstream version 1.26.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 19:02:15 +01:00
parent 79468558b6
commit c35ab76feb
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
23 changed files with 328 additions and 52 deletions

View file

@ -9,16 +9,16 @@ jobs:
linux:
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
python-version: ['3.7', '3.8', '3.9', '3.10']
include:
- python-version: 3.6
- python-version: '3.7'
os: ubuntu-18.04 # MySQL 5.7.32
- python-version: 3.7
- python-version: '3.8'
os: ubuntu-18.04 # MySQL 5.7.32
- python-version: 3.8
os: ubuntu-18.04 # MySQL 5.7.32
- python-version: 3.9
- python-version: '3.9'
os: ubuntu-20.04 # MySQL 8.0.22
- python-version: '3.10'
os: ubuntu-22.04 # MySQL 8.0.28
runs-on: ${{ matrix.os }}
steps:

View file

@ -95,7 +95,7 @@ credentials to use by setting the applicable environment variables:
```bash
$ export PYTEST_HOST=localhost
$ export PYTEST_USER=user
$ export PYTEST_USER=mycli
$ export PYTEST_PASSWORD=myclirocks
$ export PYTEST_PORT=3306
$ export PYTEST_CHARSET=utf8
@ -104,6 +104,14 @@ $ export PYTEST_CHARSET=utf8
The default values are `localhost`, `root`, no password, `3306`, and `utf8`.
You only need to set the values that differ from the defaults.
If you would like to run the tests as a user with only the necessary privileges,
create a `mycli` user and run the following grant statements.
```sql
GRANT ALL PRIVILEGES ON `mycli_%`.* TO 'mycli'@'localhost';
GRANT SELECT ON mysql.* TO 'mycli'@'localhost';
GRANT SELECT ON performance_schema.* TO 'mycli'@'localhost';
```
### CLI Tests

View file

@ -69,6 +69,8 @@ $ sudo apt-get install mycli # Only on debian or ubuntu
--ssh-config-host TEXT Host to connect to ssh server reading from ssh
configuration.
--ssl Enable SSL for connection (automatically
enabled with other flags).
--ssl-ca PATH CA file in PEM format.
--ssl-capath TEXT CA directory.
--ssl-cert PATH X509 cert in PEM format.
@ -133,6 +135,7 @@ Features
* Log every query and its results to a file (disabled by default).
* Pretty prints tabular data (with colors!)
* Support for SSL connections
* Some features are only exposed as [key bindings](doc/key_bindings.rst)
Contributions:
--------------
@ -151,6 +154,22 @@ Twitter: [@amjithr](http://twitter.com/amjithr)
## Detailed Install Instructions:
### Arch, Manjaro
You can install the mycli package available in the AUR:
```
$ yay -S mycli
```
### Debian, Ubuntu
On Debian, Ubuntu distributions, you can easily install the mycli package using apt:
```
$ sudo apt-get install mycli
```
### Fedora
Fedora has a package available for mycli, install it using dnf:
@ -164,13 +183,13 @@ $ sudo dnf install mycli
I haven't built an RPM package for mycli for RHEL or Centos yet. So please use `pip` to install `mycli`. You can install pip on your system using:
```
$ sudo yum install python-pip
$ sudo yum install python3-pip
```
Once that is installed, you can install mycli as follows:
```
$ sudo pip install mycli
$ sudo pip3 install mycli
```
### Windows
@ -201,7 +220,7 @@ Thanks to [PyMysql](https://github.com/PyMySQL/PyMySQL) for a pure python adapte
### Compatibility
Mycli is tested on macOS and Linux.
Mycli is tested on macOS and Linux, and requires Python 3.7 or better.
**Mycli is not tested on Windows**, but the libraries used in this app are Windows-compatible.
This means it should work without any modifications. If you're unable to run it

View file

@ -1,3 +1,36 @@
1.26.1 (2022/09/01)
===
Bug Fixes:
----------
* Require Python 3.7 in `setup.py`
1.26.0 (2022/09/01)
===================
Features:
---------
* Add `--ssl` flag to enable ssl/tls.
* Add `pager` option to `~/.myclirc`, for instance `pager = 'pspg --csv'` (Thanks: [BuonOmo])
* Add prettify/unprettify keybindings to format the current statement using `sqlglot`.
Internal:
---------
* Pin `cryptography` to suppress `paramiko` warning, helping CI complete and presumably affecting some users.
* Upgrade some dev requirements
* Change tests to always use databases prefixed with 'mycli_' for better security
Bug Fixes:
----------
* Support for some MySQL compatible databases, which may not implement connection_id().
* Fix the status command to work with missing 'Flush_commands' (mariadb)
* Ignore the user of the system [myslqd] config.
1.25.0 (2022/04/02)
===================
@ -18,6 +51,7 @@ Bug Fixes:
* Change in main.py - Replace the `click.get_terminal_size()` with `shutil.get_terminal_size()`
1.24.3 (2022/01/20)
===================
@ -872,6 +906,7 @@ Bug Fixes:
[Amjith Ramanujam]: https://blog.amjith.com
[Artem Bezsmertnyi]: https://github.com/mrdeathless
[BuonOmo]: https://github.com/BuonOmo
[Carlos Afonso]: https://github.com/afonsocarlos
[Casper Langemeijer]: https://github.com/langemeijer
[Daniel West]: http://github.com/danieljwest

65
doc/key_bindings.rst Normal file
View file

@ -0,0 +1,65 @@
*************
Key Bindings:
*************
Most key bindings are simply inherited from `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/index.html>`_ .
The following key bindings are special to mycli:
###
F2
###
Enable/Disable SmartCompletion Mode.
###
F3
###
Enable/Disable Multiline Mode.
###
F4
###
Toggle between Vi and Emacs mode.
###
Tab
###
Force autocompletion at cursor.
#######
C-space
#######
Initialize autocompletion at cursor.
If the autocompletion menu is not showing, display it with the appropriate completions for the context.
If the menu is showing, select the next completion.
#########
ESC Enter
#########
Introduce a line break in multi-line mode, or dispatch the command in single-line mode.
The sequence ESC-Enter is often sent by Alt-Enter.
#################################
C-x p (Emacs-mode) or > (Vi-mode)
#################################
Prettify and indent current statement, usually into multiple lines.
Only accepts buffers containing single SQL statements.
#################################
C-x u (Emacs-mode) or < (Vi-mode)
#################################
Unprettify and dedent current statement, usually into one line.
Only accepts buffers containing single SQL statements.

View file

@ -24,10 +24,12 @@ Contributors:
* Artem Bezsmertnyi
* bitkeen
* bjarnagin
* BuonOmo
* caitinggui
* Carlos Afonso
* Casper Langemeijer
* chainkite
* Claude Becker
* Colin Caine
* cxbig
* Daniel Black
@ -38,6 +40,7 @@ Contributors:
* Georgy Frolov
* Heath Naylor
* Huachao Mao
* Ishaan Bhimwal
* Jakub Boukal
* jbruno
* Jerome Provensal
@ -81,6 +84,7 @@ Contributors:
* xeron
* Yang Zou
* Yasuhiro Matsumoto
* Yuanchun Shang
* Zach DeCook
* Zane C. Bowers-Hadley
* zer09
@ -88,6 +92,8 @@ Contributors:
* Zhidong
* Zhongyang Guan
* Arvind Mishra
* Kevin Schmeichel
* Mel Dafert
Created by:
-----------

View file

@ -1 +1 @@
__version__ = '1.25.0'
__version__ = '1.26.1'

View file

@ -30,6 +30,11 @@ def create_toolbar_tokens_func(mycli, show_fish_help):
'Vi-mode ({})'.format(_get_vi_mode())
))
if mycli.toolbar_error_message:
result.append(
('class:bottom-toolbar', ' ' + mycli.toolbar_error_message))
mycli.toolbar_error_message = None
if show_fish_help():
result.append(
('class:bottom-toolbar', ' Right-arrow to complete suggestion'))

View file

@ -47,7 +47,7 @@ class CompletionRefresher(object):
def _bg_refresh(self, sqlexecute, callbacks, completer_options):
completer = SQLCompleter(**completer_options)
# Create a new pgexecute method to popoulate the completions.
# Create a new pgexecute method to populate the completions.
e = sqlexecute
executor = SQLExecute(e.dbname, e.user, e.password, e.host, e.port,
e.socket, e.charset, e.local_infile, e.ssl,

View file

@ -1,6 +1,6 @@
import logging
from prompt_toolkit.enums import EditingMode
from prompt_toolkit.filters import completion_is_selected
from prompt_toolkit.filters import completion_is_selected, emacs_mode, vi_mode
from prompt_toolkit.key_binding import KeyBindings
_logger = logging.getLogger(__name__)
@ -61,6 +61,48 @@ def mycli_bindings(mycli):
else:
b.start_completion(select_first=False)
@kb.add('>', filter=vi_mode)
@kb.add('c-x', 'p', filter=emacs_mode)
def _(event):
"""
Prettify and indent current statement, usually into multiple lines.
Only accepts buffers containing single SQL statements.
"""
_logger.debug('Detected <C-x p>/> key.')
b = event.app.current_buffer
cursorpos_relative = b.cursor_position / len(b.text)
pretty_text = mycli.handle_prettify_binding(b.text)
if len(pretty_text) > 0:
b.text = pretty_text
cursorpos_abs = int(round(cursorpos_relative * len(b.text)))
while 0 < cursorpos_abs < len(b.text) \
and b.text[cursorpos_abs] in (' ', '\n'):
cursorpos_abs -= 1
b.cursor_position = min(cursorpos_abs, len(b.text))
@kb.add('<', filter=vi_mode)
@kb.add('c-x', 'u', filter=emacs_mode)
def _(event):
"""
Unprettify and dedent current statement, usually into one line.
Only accepts buffers containing single SQL statements.
"""
_logger.debug('Detected <C-x u>/< key.')
b = event.app.current_buffer
cursorpos_relative = b.cursor_position / len(b.text)
unpretty_text = mycli.handle_unprettify_binding(b.text)
if len(unpretty_text) > 0:
b.text = unpretty_text
cursorpos_abs = int(round(cursorpos_relative * len(b.text)))
while 0 < cursorpos_abs < len(b.text) \
and b.text[cursorpos_abs] in (' ', '\n'):
cursorpos_abs -= 1
b.cursor_position = min(cursorpos_abs, len(b.text))
@kb.add('enter', filter=completion_is_selected)
def _(event):
"""Makes the enter key work as the tab key only when showing the menu.

View file

@ -24,6 +24,7 @@ from cli_helpers.tabular_output import preprocessors
from cli_helpers.utils import strip_ansi
import click
import sqlparse
import sqlglot
from mycli.packages.parseutils import is_dropping_database, is_destructive
from prompt_toolkit.completion import DynamicCompleter
from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
@ -123,6 +124,7 @@ class MyCli(object):
self.logfile = logfile
self.defaults_suffix = defaults_suffix
self.login_path = login_path
self.toolbar_error_message = None
# self.cnf_files is a class variable that stores the list of mysql
# config files to read in at launch.
@ -341,6 +343,7 @@ class MyCli(object):
'mysqld': {
'socket': 'default_socket',
'port': 'default_port',
'user': 'default_user',
},
}
@ -447,7 +450,7 @@ class MyCli(object):
if not any(v for v in ssl.values()):
ssl = None
# if the passwd is not specfied try to set it using the password_file option
# if the passwd is not specified try to set it using the password_file option
password_from_file = self.get_password_from_file(password_file)
passwd = passwd or password_from_file
@ -581,6 +584,34 @@ class MyCli(object):
return True
return False
def handle_prettify_binding(self, text):
try:
statements = sqlglot.parse(text, read='mysql')
except Exception as e:
statements = []
if len(statements) == 1:
pretty_text = statements[0].sql(pretty=True, pad=4, dialect='mysql')
else:
pretty_text = ''
self.toolbar_error_message = 'Prettify failed to parse statement'
if len(pretty_text) > 0:
pretty_text = pretty_text + ';'
return pretty_text
def handle_unprettify_binding(self, text):
try:
statements = sqlglot.parse(text, read='mysql')
except Exception as e:
statements = []
if len(statements) == 1:
unpretty_text = statements[0].sql(pretty=False, dialect='mysql')
else:
unpretty_text = ''
self.toolbar_error_message = 'Unprettify failed to parse statement'
if len(unpretty_text) > 0:
unpretty_text = unpretty_text + ';'
return unpretty_text
def run_cli(self):
iterations = 0
sqlexecute = self.sqlexecute
@ -723,7 +754,7 @@ class MyCli(object):
except KeyboardInterrupt:
pass
if self.beep_after_seconds > 0 and t >= self.beep_after_seconds:
self.echo('\a', err=True, nl=False)
self.bell()
if special.is_timing_enabled():
self.echo('Time: %0.03fs' % t)
except KeyboardInterrupt:
@ -739,6 +770,8 @@ class MyCli(object):
except KeyboardInterrupt:
# get last connection id
connection_id_to_kill = sqlexecute.connection_id
# some mysql compatible databases may not implemente connection_id()
if connection_id_to_kill > 0:
logger.debug("connection id to kill: %r", connection_id_to_kill)
# Restart connection to the database
sqlexecute.connect()
@ -752,6 +785,8 @@ class MyCli(object):
except Exception as e:
self.echo('Encountered error while cancelling query: {}'.format(e),
err=True, fg='red')
else:
logger.debug("Did not get a connection id, skip cancelling query")
except NotImplementedError:
self.echo('Not Yet Implemented.', fg="yellow")
except OperationalError as e:
@ -860,6 +895,11 @@ class MyCli(object):
self.log_output(s)
click.secho(s, **kwargs)
def bell(self):
"""Print a bell on the stderr.
"""
click.secho('\a', err=True, nl=False)
def get_output_margin(self, status=None):
"""Get the output margin (number of rows for the prompt, footer and
timing message."""
@ -933,8 +973,9 @@ class MyCli(object):
os.environ['LESS'] = '-RXF'
cnf = self.read_my_cnf_files(self.cnf_files, ['pager', 'skip-pager'])
if cnf['pager']:
special.set_pager(cnf['pager'])
cnf_pager = cnf['pager'] or self.config['main']['pager']
if cnf_pager:
special.set_pager(cnf_pager)
self.explicit_pager = True
else:
self.explicit_pager = False
@ -1084,6 +1125,8 @@ class MyCli(object):
@click.option('--ssh-config-path', help='Path to ssh configuration.',
default=os.path.expanduser('~') + '/.ssh/config')
@click.option('--ssh-config-host', help='Host to connect to ssh server reading from ssh configuration.')
@click.option('--ssl', 'ssl_enable', is_flag=True,
help='Enable SSL for connection (automatically enabled with other flags).')
@click.option('--ssl-ca', help='CA file in PEM format.',
type=click.Path(exists=True))
@click.option('--ssl-capath', help='CA directory.')
@ -1142,7 +1185,7 @@ class MyCli(object):
def cli(database, user, host, port, socket, password, dbname,
version, verbose, prompt, logfile, defaults_group_suffix,
defaults_file, login_path, auto_vertical_output, local_infile,
ssl_ca, ssl_capath, ssl_cert, ssl_key, ssl_cipher,
ssl_enable, ssl_ca, ssl_capath, ssl_cert, ssl_key, ssl_cipher,
ssl_verify_server_cert, table, csv, warn, execute, myclirc, dsn,
list_dsn, ssh_user, ssh_host, ssh_port, ssh_password,
ssh_key_filename, list_ssh_config, ssh_config_path, ssh_config_host,
@ -1197,6 +1240,7 @@ def cli(database, user, host, port, socket, password, dbname,
database = dbname or database
ssl = {
'enable': ssl_enable,
'ca': ssl_ca and os.path.expanduser(ssl_ca),
'cert': ssl_cert and os.path.expanduser(ssl_cert),
'key': ssl_key and os.path.expanduser(ssl_key),

View file

@ -27,7 +27,7 @@ log_level = INFO
# line below.
# audit_log = ~/.mycli-audit.log
# Timing of sql statments and table rendering.
# Timing of sql statements and table rendering.
timing = True
# Beep after long-running queries are completed; 0 to disable.
@ -66,7 +66,7 @@ wider_completion_menu = False
# \R - The current time, in 24-hour military time (0-23)
# \r - The current time, standard 12-hour time (1-12)
# \s - Seconds of the current time
# \t - Product type (Percona, MySQL, MariaDB)
# \t - Product type (Percona, MySQL, MariaDB, TiDB)
# \A - DSN alias name (from the [alias_dsn] section)
# \u - Username
# \x1b[...m - insert ANSI escape sequence
@ -89,6 +89,9 @@ keyword_casing = auto
# disabled pager on startup
enable_pager = True
# Choose a specific pager
pager = 'less'
# Custom colors for the completion menu, toolbar, etc.
[colors]
completion-menu.completion.current = 'bg:#ffffff #000000'

View file

@ -129,6 +129,8 @@ def suggest_based_on_last_token(token, text_before_cursor, full_text, identifier
prev_keyword, text_before_cursor = find_prev_keyword(text_before_cursor)
return suggest_based_on_last_token(prev_keyword, text_before_cursor,
full_text, identifier)
elif token is None:
return [{'type': 'keyword'}]
else:
token_v = token.value.lower()

View file

@ -143,7 +143,7 @@ def extract_table_identifiers(token_stream):
# extract_tables is inspired from examples in the sqlparse lib.
def extract_tables(sql):
"""Extract the table names from an SQL statment.
"""Extract the table names from an SQL statement.
Returns a list of (schema, table, alias) tuples

View file

@ -34,6 +34,7 @@ def list_tables(cur, arg=None, arg_type=PARSED_QUERY, verbose=False):
return [(None, tables, headers, status)]
@special_command('\\l', '\\l', 'List databases.', arg_type=RAW_QUERY, case_sensitive=True)
def list_databases(cur, **_):
query = 'SHOW DATABASES'
@ -45,6 +46,7 @@ def list_databases(cur, **_):
else:
return [(None, None, None, '')]
@special_command('status', '\\s', 'Get status information from the server.',
arg_type=RAW_QUERY, aliases=('\\s', ), case_sensitive=True)
def status(cur, **_):
@ -146,6 +148,7 @@ def status(cur, **_):
stats.append('Queries: {0}'.format(status['Queries']))
stats.append('Slow queries: {0}'.format(status['Slow_queries']))
stats.append('Opens: {0}'.format(status['Opened_tables']))
if 'Flush_commands' in status:
stats.append('Flush tables: {0}'.format(status['Flush_commands']))
stats.append('Open tables: {0}'.format(status['Open_tables']))
if 'Queries' in status:

View file

@ -28,6 +28,7 @@ class ServerSpecies(enum.Enum):
MySQL = 'MySQL'
MariaDB = 'MariaDB'
Percona = 'Percona'
TiDB = 'TiDB'
Unknown = 'MySQL'
@ -55,6 +56,7 @@ class ServerInfo:
re_species = (
(r'(?P<version>[0-9\.]+)-MariaDB', ServerSpecies.MariaDB),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-TiDB', ServerSpecies.TiDB),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[0-9]+$)',
ServerSpecies.Percona),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[A-Za-z0-9_]+)',
@ -338,9 +340,15 @@ class SQLExecute(object):
def reset_connection_id(self):
# Remember current connection id
_logger.debug('Get current connection id')
try:
res = self.run('select connection_id()')
for title, cur, headers, status in res:
self.connection_id = cur.fetchone()[0]
except Exception as e:
# See #1054
self.connection_id = -1
_logger.error('Failed to get connection id: %s', e)
else:
_logger.debug('Current connection id: %s', self.connection_id)
def change_db(self, db):

View file

@ -10,4 +10,8 @@ autopep8==1.3.3
colorama>=0.4.1
git+https://github.com/hayd/pep8radius.git # --error-status option not released
click>=7.0
paramiko==2.7.1
paramiko==2.11.0
pyperclip>=1.8.1
importlib_resources>=5.0.0
pyaes>=1.6.1
sqlglot>=5.1.3

View file

@ -18,12 +18,15 @@ description = 'CLI for MySQL Database. With auto-completion and syntax highlight
install_requirements = [
'click >= 7.0',
'cryptography >= 1.0.0',
# Temporary to suppress paramiko Blowfish warning which breaks CI.
# Pinning cryptography should not be needed after paramiko 2.11.0.
'cryptography == 36.0.2',
# 'Pygments>=1.6,<=2.11.1',
'Pygments>=1.6',
'prompt_toolkit>=3.0.6,<4.0.0',
'PyMySQL >= 0.9.2',
'sqlparse>=0.3.0,<0.5.0',
'sqlglot>=5.1.3',
'configobj >= 5.0.5',
'cli_helpers[styles] >= 2.2.1',
'pyperclip >= 1.8.1',
@ -101,16 +104,17 @@ setup(
'console_scripts': ['mycli = mycli.main:cli'],
},
cmdclass={'lint': lint, 'test': test},
python_requires=">=3.6",
python_requires=">=3.7",
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: Unix',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: SQL',
'Topic :: Database',
'Topic :: Database :: Front-Ends',

View file

@ -6,8 +6,8 @@ import mycli.sqlexecute
@pytest.fixture(scope="function")
def connection():
create_db('_test_db')
connection = db_connection('_test_db')
create_db('mycli_test_db')
connection = db_connection('mycli_test_db')
yield connection
connection.close()
@ -22,7 +22,7 @@ def cursor(connection):
@pytest.fixture
def executor(connection):
return mycli.sqlexecute.SQLExecute(
database='_test_db', user=USER,
database='mycli_test_db', user=USER,
host=HOST, password=PASSWORD, port=PORT, socket=None, charset=CHARSET,
local_infile=False, ssl=None, ssh_user=SSH_USER, ssh_host=SSH_HOST,
ssh_port=SSH_PORT, ssh_password=None, ssh_key_filename=None

View file

@ -542,7 +542,14 @@ def test_favorite_name_suggestion(expression):
suggestions = suggest_type(expression, expression)
assert suggestions == [{'type': 'favoritequery'}]
def test_order_by():
text = 'select * from foo order by '
suggestions = suggest_type(text, text)
assert suggestions == [{'tables': [(None, 'foo', None)], 'type': 'column'}]
def test_quoted_where():
text = "'where i=';"
suggestions = suggest_type(text, text)
assert suggestions == [{'type': 'keyword'}]

View file

@ -25,7 +25,7 @@ os.environ['MYSQL_TEST_LOGIN_FILE'] = login_path_file
CLI_ARGS = ['--user', USER, '--host', HOST, '--port', PORT,
'--password', PASSWORD, '--myclirc', default_config_file,
'--defaults-file', default_config_file,
'_test_db']
'mycli_test_db']
@dbtest
@ -283,6 +283,20 @@ def test_list_dsn():
assert result.output == "test : mysql://test/test\n"
def test_prettify_statement():
statement = 'SELECT 1'
m = MyCli()
pretty_statement = m.handle_prettify_binding(statement)
assert pretty_statement == 'SELECT\n 1;'
def test_unprettify_statement():
statement = 'SELECT\n 1'
m = MyCli()
unpretty_statement = m.handle_unprettify_binding(statement)
assert unpretty_statement == 'SELECT 1;'
def test_list_ssh_config():
runner = CliRunner()
with NamedTemporaryFile(mode="w") as ssh_config:
@ -305,19 +319,25 @@ def test_dsn(monkeypatch):
# Setup classes to mock mycli.main.MyCli
class Formatter:
format_name = None
class Logger:
def debug(self, *args, **args_dict):
pass
def warning(self, *args, **args_dict):
pass
class MockMyCli:
config = {'alias_dsn': {}}
def __init__(self, **args):
self.logger = Logger()
self.destructive_warning = False
self.formatter = Formatter()
def connect(self, **args):
MockMyCli.connect_args = args
def run_query(self, query, new_line=True):
pass

View file

@ -71,7 +71,7 @@ def test_table_and_columns_query(executor):
@dbtest
def test_database_list(executor):
databases = executor.databases()
assert '_test_db' in databases
assert 'mycli_test_db' in databases
@dbtest
@ -276,6 +276,7 @@ def test_multiple_results(executor):
@pytest.mark.parametrize(
'version_string, species, parsed_version_string, version',
(
('5.7.25-TiDB-v6.1.0','TiDB', '5.7.25', 50725),
('5.7.32-35', 'Percona', '5.7.32', 50732),
('5.7.32-0ubuntu0.18.04.1', 'MySQL', '5.7.32', 50732),
('10.5.8-MariaDB-1:10.5.8+maria~focal', 'MariaDB', '10.5.8', 100508),

View file

@ -41,8 +41,8 @@ dbtest = pytest.mark.skipif(
def create_db(dbname):
with db_connection().cursor() as cur:
try:
cur.execute('''DROP DATABASE IF EXISTS _test_db''')
cur.execute('''CREATE DATABASE _test_db''')
cur.execute('''DROP DATABASE IF EXISTS mycli_test_db''')
cur.execute('''CREATE DATABASE mycli_test_db''')
except:
pass