1
0
Fork 0

Merging upstream version 1.27.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 19:09:59 +01:00
parent f9b72e95f7
commit c3fea970b3
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
18 changed files with 474 additions and 94 deletions

View file

@ -9,7 +9,12 @@ jobs:
linux: linux:
strategy: strategy:
matrix: matrix:
python-version: ['3.7', '3.8', '3.9', '3.10'] python-version: [
'3.7',
'3.8',
'3.9',
'3.10',
]
include: include:
- python-version: '3.7' - python-version: '3.7'
os: ubuntu-18.04 # MySQL 5.7.32 os: ubuntu-18.04 # MySQL 5.7.32
@ -61,4 +66,3 @@ jobs:
run: | run: |
coverage combine coverage combine
coverage report coverage report
codecov

41
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: "CodeQL"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: "12 18 * * 1"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ python ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

View file

@ -1,6 +1,23 @@
1.27.0 (2023/08/11)
===================
Features:
---------
* Detect TiDB instance, show in the prompt, and use additional keywords.
* Fix the completion order to show more commonly-used keywords at the top.
Bug Fixes:
----------
* Better handle empty statements in un/prettify
* Remove vi-mode bindings for prettify/unprettify.
* Honor `\G` when executing from commandline with `-e`.
* Correctly report the version of TiDB.
1.26.1 (2022/09/01) 1.26.1 (2022/09/01)
=== ===================
Bug Fixes: Bug Fixes:
---------- ----------

View file

@ -48,17 +48,17 @@ Introduce a line break in multi-line mode, or dispatch the command in single-lin
The sequence ESC-Enter is often sent by Alt-Enter. The sequence ESC-Enter is often sent by Alt-Enter.
################################# ##################
C-x p (Emacs-mode) or > (Vi-mode) C-x p (Emacs-mode)
################################# ##################
Prettify and indent current statement, usually into multiple lines. Prettify and indent current statement, usually into multiple lines.
Only accepts buffers containing single SQL statements. Only accepts buffers containing single SQL statements.
################################# ##################
C-x u (Emacs-mode) or < (Vi-mode) C-x u (Emacs-mode)
################################# ##################
Unprettify and dedent current statement, usually into one line. Unprettify and dedent current statement, usually into one line.

View file

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

View file

@ -3,7 +3,7 @@ from .packages.special.main import COMMANDS
from collections import OrderedDict from collections import OrderedDict
from .sqlcompleter import SQLCompleter from .sqlcompleter import SQLCompleter
from .sqlexecute import SQLExecute from .sqlexecute import SQLExecute, ServerSpecies
class CompletionRefresher(object): class CompletionRefresher(object):
@ -113,6 +113,8 @@ def refresh_users(completer, executor):
@refresher('functions') @refresher('functions')
def refresh_functions(completer, executor): def refresh_functions(completer, executor):
completer.extend_functions(executor.functions()) completer.extend_functions(executor.functions())
if executor.server_info.species == ServerSpecies.TiDB:
completer.extend_functions(completer.tidb_functions, builtin=True)
@refresher('special_commands') @refresher('special_commands')
def refresh_special(completer, executor): def refresh_special(completer, executor):
@ -121,3 +123,8 @@ def refresh_special(completer, executor):
@refresher('show_commands') @refresher('show_commands')
def refresh_show_commands(completer, executor): def refresh_show_commands(completer, executor):
completer.extend_show_items(executor.show_candidates()) completer.extend_show_items(executor.show_candidates())
@refresher('keywords')
def refresh_keywords(completer, executor):
if executor.server_info.species == ServerSpecies.TiDB:
completer.extend_keywords(completer.tidb_keywords, replace=True)

View file

@ -1,6 +1,6 @@
import logging import logging
from prompt_toolkit.enums import EditingMode from prompt_toolkit.enums import EditingMode
from prompt_toolkit.filters import completion_is_selected, emacs_mode, vi_mode from prompt_toolkit.filters import completion_is_selected, emacs_mode
from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.key_binding import KeyBindings
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -61,7 +61,6 @@ def mycli_bindings(mycli):
else: else:
b.start_completion(select_first=False) b.start_completion(select_first=False)
@kb.add('>', filter=vi_mode)
@kb.add('c-x', 'p', filter=emacs_mode) @kb.add('c-x', 'p', filter=emacs_mode)
def _(event): def _(event):
""" """
@ -72,7 +71,7 @@ def mycli_bindings(mycli):
_logger.debug('Detected <C-x p>/> key.') _logger.debug('Detected <C-x p>/> key.')
b = event.app.current_buffer b = event.app.current_buffer
cursorpos_relative = b.cursor_position / len(b.text) cursorpos_relative = b.cursor_position / max(1, len(b.text))
pretty_text = mycli.handle_prettify_binding(b.text) pretty_text = mycli.handle_prettify_binding(b.text)
if len(pretty_text) > 0: if len(pretty_text) > 0:
b.text = pretty_text b.text = pretty_text
@ -82,7 +81,6 @@ def mycli_bindings(mycli):
cursorpos_abs -= 1 cursorpos_abs -= 1
b.cursor_position = min(cursorpos_abs, len(b.text)) b.cursor_position = min(cursorpos_abs, len(b.text))
@kb.add('<', filter=vi_mode)
@kb.add('c-x', 'u', filter=emacs_mode) @kb.add('c-x', 'u', filter=emacs_mode)
def _(event): def _(event):
""" """
@ -93,7 +91,7 @@ def mycli_bindings(mycli):
_logger.debug('Detected <C-x u>/< key.') _logger.debug('Detected <C-x u>/< key.')
b = event.app.current_buffer b = event.app.current_buffer
cursorpos_relative = b.cursor_position / len(b.text) cursorpos_relative = b.cursor_position / max(1, len(b.text))
unpretty_text = mycli.handle_unprettify_binding(b.text) unpretty_text = mycli.handle_unprettify_binding(b.text)
if len(unpretty_text) > 0: if len(unpretty_text) > 0:
b.text = unpretty_text b.text = unpretty_text

View file

@ -19,8 +19,16 @@ def load_ipython_extension(ipython):
def mycli_line_magic(line): def mycli_line_magic(line):
_logger.debug('mycli magic called: %r', line) _logger.debug('mycli magic called: %r', line)
parsed = sql.parse.parse(line, {}) parsed = sql.parse.parse(line, {})
conn = sql.connection.Connection(parsed['connection']) # "get" was renamed to "set" in ipython-sql:
# https://github.com/catherinedevlin/ipython-sql/commit/f4283c65aaf68f961e84019e8b939e4a3c501d43
if hasattr(sql.connection.Connection, "get"):
conn = sql.connection.Connection.get(parsed["connection"])
else:
try:
conn = sql.connection.Connection.set(parsed["connection"])
# a new positional argument was added to Connection.set in version 0.4.0 of ipython-sql
except TypeError:
conn = sql.connection.Connection.set(parsed["connection"], False)
try: try:
# A corresponding mycli object already exists # A corresponding mycli object already exists
mycli = conn._mycli mycli = conn._mycli

View file

@ -589,7 +589,7 @@ class MyCli(object):
statements = sqlglot.parse(text, read='mysql') statements = sqlglot.parse(text, read='mysql')
except Exception as e: except Exception as e:
statements = [] statements = []
if len(statements) == 1: if len(statements) == 1 and statements[0]:
pretty_text = statements[0].sql(pretty=True, pad=4, dialect='mysql') pretty_text = statements[0].sql(pretty=True, pad=4, dialect='mysql')
else: else:
pretty_text = '' pretty_text = ''
@ -603,7 +603,7 @@ class MyCli(object):
statements = sqlglot.parse(text, read='mysql') statements = sqlglot.parse(text, read='mysql')
except Exception as e: except Exception as e:
statements = [] statements = []
if len(statements) == 1: if len(statements) == 1 and statements[0]:
unpretty_text = statements[0].sql(pretty=False, dialect='mysql') unpretty_text = statements[0].sql(pretty=False, dialect='mysql')
else: else:
unpretty_text = '' unpretty_text = ''
@ -1038,7 +1038,7 @@ class MyCli(object):
for result in results: for result in results:
title, cur, headers, status = result title, cur, headers, status = result
self.formatter.query = query self.formatter.query = query
output = self.format_output(title, cur, headers) output = self.format_output(title, cur, headers, special.is_expanded_output())
for line in output: for line in output:
click.echo(line, nl=new_line) click.echo(line, nl=new_line)
@ -1331,7 +1331,12 @@ def cli(database, user, host, port, socket, password, dbname,
try: try:
if csv: if csv:
mycli.formatter.format_name = 'csv' mycli.formatter.format_name = 'csv'
elif not table: if execute.endswith(r'\G'):
execute = execute[:-2]
elif table:
if execute.endswith(r'\G'):
execute = execute[:-2]
else:
mycli.formatter.format_name = 'tsv' mycli.formatter.format_name = 'tsv'
mycli.run_query(execute) mycli.run_query(execute)

View file

@ -13,33 +13,178 @@ _logger = logging.getLogger(__name__)
class SQLCompleter(Completer): class SQLCompleter(Completer):
keywords = ['ACCESS', 'ADD', 'ALL', 'ALTER TABLE', 'AND', 'ANY', 'AS', keywords = [
'ASC', 'AUTO_INCREMENT', 'BEFORE', 'BEGIN', 'BETWEEN', 'SELECT', 'FROM', 'WHERE', 'UPDATE', 'DELETE FROM', 'GROUP BY',
'BIGINT', 'BINARY', 'BY', 'CASE', 'CHANGE MASTER TO', 'CHAR', 'JOIN', 'INSERT INTO', 'LIKE', 'LIMIT', 'ACCESS', 'ADD', 'ALL',
'CHARACTER SET', 'CHECK', 'COLLATE', 'COLUMN', 'COMMENT', 'ALTER TABLE', 'AND', 'ANY', 'AS', 'ASC', 'AUTO_INCREMENT',
'COMMIT', 'CONSTRAINT', 'CREATE', 'CURRENT', 'BEFORE', 'BEGIN', 'BETWEEN', 'BIGINT', 'BINARY', 'BY', 'CASE',
'CURRENT_TIMESTAMP', 'DATABASE', 'DATE', 'DECIMAL', 'DEFAULT', 'CHANGE MASTER TO', 'CHAR', 'CHARACTER SET', 'CHECK', 'COLLATE',
'DELETE FROM', 'DESC', 'DESCRIBE', 'DROP', 'COLUMN', 'COMMENT', 'COMMIT', 'CONSTRAINT', 'CREATE', 'CURRENT',
'ELSE', 'END', 'ENGINE', 'ESCAPE', 'EXISTS', 'FILE', 'FLOAT', 'CURRENT_TIMESTAMP', 'DATABASE', 'DATE', 'DECIMAL', 'DEFAULT',
'FOR', 'FOREIGN KEY', 'FORMAT', 'FROM', 'FULL', 'FUNCTION', 'DESC', 'DESCRIBE', 'DROP', 'ELSE', 'END', 'ENGINE', 'ESCAPE',
'GRANT', 'GROUP BY', 'HAVING', 'HOST', 'IDENTIFIED', 'IN', 'EXISTS', 'FILE', 'FLOAT', 'FOR', 'FOREIGN KEY', 'FORMAT', 'FULL',
'INCREMENT', 'INDEX', 'INSERT INTO', 'INT', 'INTEGER', 'FUNCTION', 'GRANT', 'HAVING', 'HOST', 'IDENTIFIED', 'IN',
'INTERVAL', 'INTO', 'IS', 'JOIN', 'KEY', 'LEFT', 'LEVEL', 'INCREMENT', 'INDEX', 'INT', 'INTEGER', 'INTERVAL', 'INTO', 'IS',
'LIKE', 'LIMIT', 'LOCK', 'LOGS', 'LONG', 'MASTER', 'KEY', 'LEFT', 'LEVEL', 'LOCK', 'LOGS', 'LONG', 'MASTER',
'MEDIUMINT', 'MODE', 'MODIFY', 'NOT', 'NULL', 'NUMBER', 'MEDIUMINT', 'MODE', 'MODIFY', 'NOT', 'NULL', 'NUMBER', 'OFFSET',
'OFFSET', 'ON', 'OPTION', 'OR', 'ORDER BY', 'OUTER', 'OWNER', 'ON', 'OPTION', 'OR', 'ORDER BY', 'OUTER', 'OWNER', 'PASSWORD',
'PASSWORD', 'PORT', 'PRIMARY', 'PRIVILEGES', 'PROCESSLIST', 'PORT', 'PRIMARY', 'PRIVILEGES', 'PROCESSLIST', 'PURGE',
'PURGE', 'REFERENCES', 'REGEXP', 'RENAME', 'REPAIR', 'RESET', 'REFERENCES', 'REGEXP', 'RENAME', 'REPAIR', 'RESET', 'REVOKE',
'REVOKE', 'RIGHT', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'RIGHT', 'ROLLBACK', 'ROW', 'ROWS', 'ROW_FORMAT', 'SAVEPOINT',
'SAVEPOINT', 'SELECT', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SESSION', 'SET', 'SHARE', 'SHOW', 'SLAVE', 'SMALLINT', 'SMALLINT',
'SLAVE', 'SMALLINT', 'SMALLINT', 'START', 'STOP', 'TABLE', 'START', 'STOP', 'TABLE', 'THEN', 'TINYINT', 'TO', 'TRANSACTION',
'THEN', 'TINYINT', 'TO', 'TRANSACTION', 'TRIGGER', 'TRUNCATE', 'TRIGGER', 'TRUNCATE', 'UNION', 'UNIQUE', 'UNSIGNED', 'USE',
'UNION', 'UNIQUE', 'UNSIGNED', 'UPDATE', 'USE', 'USER', 'USER', 'USING', 'VALUES', 'VARCHAR', 'VIEW', 'WHEN', 'WITH'
'USING', 'VALUES', 'VARCHAR', 'VIEW', 'WHEN', 'WHERE', 'WITH'] ]
tidb_keywords = [
"SELECT", "FROM", "WHERE", "DELETE FROM", "UPDATE", "GROUP BY",
"JOIN", "INSERT INTO", "LIKE", "LIMIT", "ACCOUNT", "ACTION", "ADD",
"ADDDATE", "ADMIN", "ADVISE", "AFTER", "AGAINST", "AGO",
"ALGORITHM", "ALL", "ALTER", "ALWAYS", "ANALYZE", "AND", "ANY",
"APPROX_COUNT_DISTINCT", "APPROX_PERCENTILE", "AS", "ASC", "ASCII",
"ATTRIBUTES", "AUTO_ID_CACHE", "AUTO_INCREMENT", "AUTO_RANDOM",
"AUTO_RANDOM_BASE", "AVG", "AVG_ROW_LENGTH", "BACKEND", "BACKUP",
"BACKUPS", "BATCH", "BEGIN", "BERNOULLI", "BETWEEN", "BIGINT",
"BINARY", "BINDING", "BINDINGS", "BINDING_CACHE", "BINLOG", "BIT",
"BIT_AND", "BIT_OR", "BIT_XOR", "BLOB", "BLOCK", "BOOL", "BOOLEAN",
"BOTH", "BOUND", "BRIEF", "BTREE", "BUCKETS", "BUILTINS", "BY",
"BYTE", "CACHE", "CALL", "CANCEL", "CAPTURE", "CARDINALITY",
"CASCADE", "CASCADED", "CASE", "CAST", "CAUSAL", "CHAIN", "CHANGE",
"CHAR", "CHARACTER", "CHARSET", "CHECK", "CHECKPOINT", "CHECKSUM",
"CIPHER", "CLEANUP", "CLIENT", "CLIENT_ERRORS_SUMMARY",
"CLUSTERED", "CMSKETCH", "COALESCE", "COLLATE", "COLLATION",
"COLUMN", "COLUMNS", "COLUMN_FORMAT", "COLUMN_STATS_USAGE",
"COMMENT", "COMMIT", "COMMITTED", "COMPACT", "COMPRESSED",
"COMPRESSION", "CONCURRENCY", "CONFIG", "CONNECTION",
"CONSISTENCY", "CONSISTENT", "CONSTRAINT", "CONSTRAINTS",
"CONTEXT", "CONVERT", "COPY", "CORRELATION", "CPU", "CREATE",
"CROSS", "CSV_BACKSLASH_ESCAPE", "CSV_DELIMITER", "CSV_HEADER",
"CSV_NOT_NULL", "CSV_NULL", "CSV_SEPARATOR",
"CSV_TRIM_LAST_SEPARATORS", "CUME_DIST", "CURRENT", "CURRENT_DATE",
"CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
"CURRENT_USER", "CURTIME", "CYCLE", "DATA", "DATABASE",
"DATABASES", "DATE", "DATETIME", "DATE_ADD", "DATE_SUB", "DAY",
"DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DDL",
"DEALLOCATE", "DECIMAL", "DEFAULT", "DEFINER", "DELAYED",
"DELAY_KEY_WRITE", "DENSE_RANK", "DEPENDENCY", "DEPTH", "DESC",
"DESCRIBE", "DIRECTORY", "DISABLE", "DISABLED", "DISCARD", "DISK",
"DISTINCT", "DISTINCTROW", "DIV", "DO", "DOT", "DOUBLE", "DRAINER",
"DROP", "DRY", "DUAL", "DUMP", "DUPLICATE", "DYNAMIC", "ELSE",
"ENABLE", "ENABLED", "ENCLOSED", "ENCRYPTION", "END", "ENFORCED",
"ENGINE", "ENGINES", "ENUM", "ERROR", "ERRORS", "ESCAPE",
"ESCAPED", "EVENT", "EVENTS", "EVOLVE", "EXACT", "EXCEPT",
"EXCHANGE", "EXCLUSIVE", "EXECUTE", "EXISTS", "EXPANSION",
"EXPIRE", "EXPLAIN", "EXPR_PUSHDOWN_BLACKLIST", "EXTENDED",
"EXTRACT", "FALSE", "FAST", "FAULTS", "FETCH", "FIELDS", "FILE",
"FIRST", "FIRST_VALUE", "FIXED", "FLASHBACK", "FLOAT", "FLUSH",
"FOLLOWER", "FOLLOWERS", "FOLLOWER_CONSTRAINTS", "FOLLOWING",
"FOR", "FORCE", "FOREIGN", "FORMAT", "FULL", "FULLTEXT",
"FUNCTION", "GENERAL", "GENERATED", "GET_FORMAT", "GLOBAL",
"GRANT", "GRANTS", "GROUPS", "GROUP_CONCAT", "HASH", "HAVING",
"HELP", "HIGH_PRIORITY", "HISTOGRAM", "HISTOGRAMS_IN_FLIGHT",
"HISTORY", "HOSTS", "HOUR", "HOUR_MICROSECOND", "HOUR_MINUTE",
"HOUR_SECOND", "IDENTIFIED", "IF", "IGNORE", "IMPORT", "IMPORTS",
"IN", "INCREMENT", "INCREMENTAL", "INDEX", "INDEXES", "INFILE",
"INNER", "INPLACE", "INSERT_METHOD", "INSTANCE",
"INSTANT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8",
"INTEGER", "INTERNAL", "INTERSECT", "INTERVAL", "INTO",
"INVISIBLE", "INVOKER", "IO", "IPC", "IS", "ISOLATION", "ISSUER",
"JOB", "JOBS", "JSON", "JSON_ARRAYAGG", "JSON_OBJECTAGG", "KEY",
"KEYS", "KEY_BLOCK_SIZE", "KILL", "LABELS", "LAG", "LANGUAGE",
"LAST", "LASTVAL", "LAST_BACKUP", "LAST_VALUE", "LEAD", "LEADER",
"LEADER_CONSTRAINTS", "LEADING", "LEARNER", "LEARNERS",
"LEARNER_CONSTRAINTS", "LEFT", "LESS", "LEVEL", "LINEAR", "LINES",
"LIST", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATION",
"LOCK", "LOCKED", "LOGS", "LONG", "LONGBLOB", "LONGTEXT",
"LOW_PRIORITY", "MASTER", "MATCH", "MAX", "MAXVALUE",
"MAX_CONNECTIONS_PER_HOUR", "MAX_IDXNUM", "MAX_MINUTES",
"MAX_QUERIES_PER_HOUR", "MAX_ROWS", "MAX_UPDATES_PER_HOUR",
"MAX_USER_CONNECTIONS", "MB", "MEDIUMBLOB", "MEDIUMINT",
"MEDIUMTEXT", "MEMORY", "MERGE", "MICROSECOND", "MIN", "MINUTE",
"MINUTE_MICROSECOND", "MINUTE_SECOND", "MINVALUE", "MIN_ROWS",
"MOD", "MODE", "MODIFY", "MONTH", "NAMES", "NATIONAL", "NATURAL",
"NCHAR", "NEVER", "NEXT", "NEXTVAL", "NEXT_ROW_ID", "NO",
"NOCACHE", "NOCYCLE", "NODEGROUP", "NODE_ID", "NODE_STATE",
"NOMAXVALUE", "NOMINVALUE", "NONCLUSTERED", "NONE", "NORMAL",
"NOT", "NOW", "NOWAIT", "NO_WRITE_TO_BINLOG", "NTH_VALUE", "NTILE",
"NULL", "NULLS", "NUMERIC", "NVARCHAR", "OF", "OFF", "OFFSET",
"ON", "ONLINE", "ONLY", "ON_DUPLICATE", "OPEN", "OPTIMISTIC",
"OPTIMIZE", "OPTION", "OPTIONAL", "OPTIONALLY",
"OPT_RULE_BLACKLIST", "OR", "ORDER", "OUTER", "OUTFILE", "OVER",
"PACK_KEYS", "PAGE", "PARSER", "PARTIAL", "PARTITION",
"PARTITIONING", "PARTITIONS", "PASSWORD", "PERCENT",
"PERCENT_RANK", "PER_DB", "PER_TABLE", "PESSIMISTIC", "PLACEMENT",
"PLAN", "PLAN_CACHE", "PLUGINS", "POLICY", "POSITION", "PRECEDING",
"PRECISION", "PREDICATE", "PREPARE", "PRESERVE",
"PRE_SPLIT_REGIONS", "PRIMARY", "PRIMARY_REGION", "PRIVILEGES",
"PROCEDURE", "PROCESS", "PROCESSLIST", "PROFILE", "PROFILES",
"PROXY", "PUMP", "PURGE", "QUARTER", "QUERIES", "QUERY", "QUICK",
"RANGE", "RANK", "RATE_LIMIT", "READ", "REAL", "REBUILD", "RECENT",
"RECOVER", "RECURSIVE", "REDUNDANT", "REFERENCES", "REGEXP",
"REGION", "REGIONS", "RELEASE", "RELOAD", "REMOVE", "RENAME",
"REORGANIZE", "REPAIR", "REPEAT", "REPEATABLE", "REPLACE",
"REPLAYER", "REPLICA", "REPLICAS", "REPLICATION", "REQUIRE",
"REQUIRED", "RESET", "RESPECT", "RESTART", "RESTORE", "RESTORES",
"RESTRICT", "RESUME", "REVERSE", "REVOKE", "RIGHT", "RLIKE",
"ROLE", "ROLLBACK", "ROUTINE", "ROW", "ROWS", "ROW_COUNT",
"ROW_FORMAT", "ROW_NUMBER", "RTREE", "RUN", "RUNNING", "S3",
"SAMPLERATE", "SAMPLES", "SAN", "SAVEPOINT", "SCHEDULE", "SECOND",
"SECONDARY_ENGINE", "SECONDARY_LOAD", "SECONDARY_UNLOAD",
"SECOND_MICROSECOND", "SECURITY", "SEND_CREDENTIALS_TO_TIKV",
"SEPARATOR", "SEQUENCE", "SERIAL", "SERIALIZABLE", "SESSION",
"SESSION_STATES", "SET", "SETVAL", "SHARD_ROW_ID_BITS", "SHARE",
"SHARED", "SHOW", "SHUTDOWN", "SIGNED", "SIMPLE", "SKIP",
"SKIP_SCHEMA_FILES", "SLAVE", "SLOW", "SMALLINT", "SNAPSHOT",
"SOME", "SOURCE", "SPATIAL", "SPLIT", "SQL", "SQL_BIG_RESULT",
"SQL_BUFFER_RESULT", "SQL_CACHE", "SQL_CALC_FOUND_ROWS",
"SQL_NO_CACHE", "SQL_SMALL_RESULT", "SQL_TSI_DAY", "SQL_TSI_HOUR",
"SQL_TSI_MINUTE", "SQL_TSI_MONTH", "SQL_TSI_QUARTER",
"SQL_TSI_SECOND", "SQL_TSI_WEEK", "SQL_TSI_YEAR", "SSL",
"STALENESS", "START", "STARTING", "STATISTICS", "STATS",
"STATS_AUTO_RECALC", "STATS_BUCKETS", "STATS_COL_CHOICE",
"STATS_COL_LIST", "STATS_EXTENDED", "STATS_HEALTHY",
"STATS_HISTOGRAMS", "STATS_META", "STATS_OPTIONS",
"STATS_PERSISTENT", "STATS_SAMPLE_PAGES", "STATS_SAMPLE_RATE",
"STATS_TOPN", "STATUS", "STD", "STDDEV", "STDDEV_POP",
"STDDEV_SAMP", "STOP", "STORAGE", "STORED", "STRAIGHT_JOIN",
"STRICT", "STRICT_FORMAT", "STRONG", "SUBDATE", "SUBJECT",
"SUBPARTITION", "SUBPARTITIONS", "SUBSTRING", "SUM", "SUPER",
"SWAPS", "SWITCHES", "SYSTEM", "SYSTEM_TIME", "TABLE", "TABLES",
"TABLESAMPLE", "TABLESPACE", "TABLE_CHECKSUM", "TARGET",
"TELEMETRY", "TELEMETRY_ID", "TEMPORARY", "TEMPTABLE",
"TERMINATED", "TEXT", "THAN", "THEN", "TIDB", "TIFLASH",
"TIKV_IMPORTER", "TIME", "TIMESTAMP", "TIMESTAMPADD",
"TIMESTAMPDIFF", "TINYBLOB", "TINYINT", "TINYTEXT", "TLS", "TO",
"TOKUDB_DEFAULT", "TOKUDB_FAST", "TOKUDB_LZMA", "TOKUDB_QUICKLZ",
"TOKUDB_SMALL", "TOKUDB_SNAPPY", "TOKUDB_UNCOMPRESSED",
"TOKUDB_ZLIB", "TOP", "TOPN", "TRACE", "TRADITIONAL", "TRAILING",
"TRANSACTION", "TRIGGER", "TRIGGERS", "TRIM", "TRUE",
"TRUE_CARD_COST", "TRUNCATE", "TYPE", "UNBOUNDED", "UNCOMMITTED",
"UNDEFINED", "UNICODE", "UNION", "UNIQUE", "UNKNOWN", "UNLOCK",
"UNSIGNED", "USAGE", "USE", "USER", "USING", "UTC_DATE",
"UTC_TIME", "UTC_TIMESTAMP", "VALIDATION", "VALUE", "VALUES",
"VARBINARY", "VARCHAR", "VARCHARACTER", "VARIABLES", "VARIANCE",
"VARYING", "VAR_POP", "VAR_SAMP", "VERBOSE", "VIEW", "VIRTUAL",
"VISIBLE", "VOTER", "VOTERS", "VOTER_CONSTRAINTS", "WAIT",
"WARNINGS", "WEEK", "WEIGHT_STRING", "WHEN", "WIDTH", "WINDOW",
"WITH", "WITHOUT", "WRITE", "X509", "XOR", "YEAR", "YEAR_MONTH",
"ZEROFILL"
]
functions = ['AVG', 'CONCAT', 'COUNT', 'DISTINCT', 'FIRST', 'FORMAT', functions = ['AVG', 'CONCAT', 'COUNT', 'DISTINCT', 'FIRST', 'FORMAT',
'FROM_UNIXTIME', 'LAST', 'LCASE', 'LEN', 'MAX', 'MID', 'FROM_UNIXTIME', 'LAST', 'LCASE', 'LEN', 'MAX', 'MID',
'MIN', 'NOW', 'ROUND', 'SUM', 'TOP', 'UCASE', 'UNIX_TIMESTAMP'] 'MIN', 'NOW', 'ROUND', 'SUM', 'TOP', 'UCASE',
'UNIX_TIMESTAMP'
]
# https://docs.pingcap.com/tidb/dev/tidb-functions
tidb_functions = [
'TIDB_BOUNDED_STALENESS', 'TIDB_DECODE_KEY', 'TIDB_DECODE_PLAN',
'TIDB_IS_DDL_OWNER', 'TIDB_PARSE_TSO', 'TIDB_VERSION',
'TIDB_DECODE_SQL_DIGESTS', 'VITESS_HASH', 'TIDB_SHARD'
]
show_items = [] show_items = []
@ -94,9 +239,12 @@ class SQLCompleter(Completer):
def extend_database_names(self, databases): def extend_database_names(self, databases):
self.databases.extend(databases) self.databases.extend(databases)
def extend_keywords(self, additional_keywords): def extend_keywords(self, keywords, replace=False):
self.keywords.extend(additional_keywords) if replace:
self.all_completions.update(additional_keywords) self.keywords = keywords
else:
self.keywords.extend(keywords)
self.all_completions.update(keywords)
def extend_show_items(self, show_items): def extend_show_items(self, show_items):
for show_item in show_items: for show_item in show_items:
@ -172,7 +320,12 @@ class SQLCompleter(Completer):
metadata[self.dbname][relname].append(column) metadata[self.dbname][relname].append(column)
self.all_completions.add(column) self.all_completions.add(column)
def extend_functions(self, func_data): def extend_functions(self, func_data, builtin=False):
# if 'builtin' is set this is extending the list of builtin functions
if builtin:
self.functions.extend(func_data)
return
# 'func_data' is a generator object. It can throw an exception while # 'func_data' is a generator object. It can throw an exception while
# being consumed. This could happen if the user has launched the app # being consumed. This could happen if the user has launched the app
# without specifying a database name. This exception must be handled to # without specifying a database name. This exception must be handled to
@ -224,13 +377,13 @@ class SQLCompleter(Completer):
if fuzzy: if fuzzy:
regex = '.*?'.join(map(escape, text)) regex = '.*?'.join(map(escape, text))
pat = compile('(%s)' % regex) pat = compile('(%s)' % regex)
for item in sorted(collection): for item in collection:
r = pat.search(item.lower()) r = pat.search(item.lower())
if r: if r:
completions.append((len(r.group()), r.start(), item)) completions.append((len(r.group()), r.start(), item))
else: else:
match_end_limit = len(text) if start_only else None match_end_limit = len(text) if start_only else None
for item in sorted(collection): for item in collection:
match_point = item.lower().find(text, 0, match_end_limit) match_point = item.lower().find(text, 0, match_end_limit)
if match_point >= 0: if match_point >= 0:
completions.append((len(text), match_point, item)) completions.append((len(text), match_point, item))
@ -244,7 +397,7 @@ class SQLCompleter(Completer):
return kw.lower() return kw.lower()
return (Completion(z if casing is None else apply_case(z), -len(text)) return (Completion(z if casing is None else apply_case(z), -len(text))
for x, y, z in sorted(completions)) for x, y, z in completions)
def get_completions(self, document, complete_event, smart_completion=None): def get_completions(self, document, complete_event, smart_completion=None):
word_before_cursor = document.get_word_before_cursor(WORD=True) word_before_cursor = document.get_word_before_cursor(WORD=True)

View file

@ -56,7 +56,7 @@ class ServerInfo:
re_species = ( re_species = (
(r'(?P<version>[0-9\.]+)-MariaDB', ServerSpecies.MariaDB), (r'(?P<version>[0-9\.]+)-MariaDB', ServerSpecies.MariaDB),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-TiDB', ServerSpecies.TiDB), (r'[0-9\.]*-TiDB-v(?P<version>[0-9\.]+)-?(?P<comment>[a-z0-9\-]*)', ServerSpecies.TiDB),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[0-9]+$)', (r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[0-9]+$)',
ServerSpecies.Percona), ServerSpecies.Percona),
(r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[A-Za-z0-9_]+)', (r'(?P<version>[0-9\.]+)[a-z0-9]*-(?P<comment>[A-Za-z0-9_]+)',

View file

@ -5,7 +5,6 @@ twine>=1.12.1
behave>=1.2.4 behave>=1.2.4
pexpect>=3.3 pexpect>=3.3
coverage>=5.0.4 coverage>=5.0.4
codecov>=2.0.9
autopep8==1.3.3 autopep8==1.3.3
colorama>=0.4.1 colorama>=0.4.1
git+https://github.com/hayd/pep8radius.git # --error-status option not released git+https://github.com/hayd/pep8radius.git # --error-status option not released

View file

@ -1,12 +1,157 @@
# vi: ft=dosini # vi: ft=dosini
# This file is loaded after mycli/myclirc and should override only those
# variables needed for testing.
# To see what every variable does see mycli/myclirc
[main] [main]
# Enables context sensitive auto-completion. If this is disabled the all
# possible completions will be listed.
smart_completion = True
# Multi-line mode allows breaking up the sql statements into multiple lines. If
# this is set to True, then the end of the statements must have a semi-colon.
# If this is set to False then sql statements can't be split into multiple
# lines. End of line (return) is considered as the end of the statement.
multi_line = False
# Destructive warning mode will alert you before executing a sql statement
# that may cause harm to the database such as "drop table", "drop database"
# or "shutdown".
destructive_warning = True
# log_file location.
log_file = ~/.mycli.test.log log_file = ~/.mycli.test.log
# Default log level. Possible values: "CRITICAL", "ERROR", "WARNING", "INFO"
# and "DEBUG". "NONE" disables logging.
log_level = DEBUG log_level = DEBUG
prompt = '\t \u@\h:\d> '
# Log every query and its results to a file. Enable this by uncommenting the
# line below.
# audit_log = ~/.mycli-audit.log
# Timing of sql statements and table rendering.
timing = True
# Beep after long-running queries are completed; 0 to disable.
beep_after_seconds = 0
# Table format. Possible values: ascii, double, github,
# psql, plain, simple, grid, fancy_grid, pipe, orgtbl, rst, mediawiki, html,
# latex, latex_booktabs, textile, moinmoin, jira, vertical, tsv, csv.
# Recommended: ascii
table_format = ascii
# Syntax coloring style. Possible values (many support the "-dark" suffix):
# manni, igor, xcode, vim, autumn, vs, rrt, native, perldoc, borland, tango, emacs,
# friendly, monokai, paraiso, colorful, murphy, bw, pastie, paraiso, trac, default,
# fruity.
# Screenshots at http://mycli.net/syntax
# Can be further modified in [colors]
syntax_style = default
# Keybindings: Possible values: emacs, vi.
# Emacs mode: Ctrl-A is home, Ctrl-E is end. All emacs keybindings are available in the REPL.
# When Vi mode is enabled you can use modal editing features offered by Vi in the REPL.
key_bindings = emacs
# Enabling this option will show the suggestions in a wider menu. Thus more items are suggested.
wider_completion_menu = False
# MySQL prompt
# \D - The full current date
# \d - Database name
# \h - Hostname of the server
# \m - Minutes of the current time
# \n - Newline
# \P - AM/PM
# \p - Port
# \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, TiDB)
# \A - DSN alias name (from the [alias_dsn] section)
# \u - Username
# \x1b[...m - insert ANSI escape sequence
prompt = "\t \u@\h:\d> "
prompt_continuation = ->
# Skip intro info on startup and outro info on exit
less_chatty = True less_chatty = True
# Use alias from --login-path instead of host name in prompt
login_path_as_host = False
# Cause result sets to be displayed vertically if they are too wide for the current window,
# and using normal tabular format otherwise. (This applies to statements terminated by ; or \G.)
auto_vertical_output = False
# keyword casing preference. Possible values "lower", "upper", "auto"
keyword_casing = auto
# disabled pager on startup
enable_pager = True
# Custom colors for the completion menu, toolbar, etc.
[colors]
completion-menu.completion.current = "bg:#ffffff #000000"
completion-menu.completion = "bg:#008888 #ffffff"
completion-menu.meta.completion.current = "bg:#44aaaa #000000"
completion-menu.meta.completion = "bg:#448888 #ffffff"
completion-menu.multi-column-meta = "bg:#aaffff #000000"
scrollbar.arrow = "bg:#003333"
scrollbar = "bg:#00aaaa"
selected = "#ffffff bg:#6666aa"
search = "#ffffff bg:#4444aa"
search.current = "#ffffff bg:#44aa44"
bottom-toolbar = "bg:#222222 #aaaaaa"
bottom-toolbar.off = "bg:#222222 #888888"
bottom-toolbar.on = "bg:#222222 #ffffff"
search-toolbar = noinherit bold
search-toolbar.text = nobold
system-toolbar = noinherit bold
arg-toolbar = noinherit bold
arg-toolbar.text = nobold
bottom-toolbar.transaction.valid = "bg:#222222 #00ff5f bold"
bottom-toolbar.transaction.failed = "bg:#222222 #ff005f bold"
# style classes for colored table output
output.header = "#00ff5f bold"
output.odd-row = ""
output.even-row = ""
output.null = "#808080"
# SQL syntax highlighting overrides
# sql.comment = 'italic #408080'
# sql.comment.multi-line = ''
# sql.comment.single-line = ''
# sql.comment.optimizer-hint = ''
# sql.escape = 'border:#FF0000'
# sql.keyword = 'bold #008000'
# sql.datatype = 'nobold #B00040'
# sql.literal = ''
# sql.literal.date = ''
# sql.symbol = ''
# sql.quoted-schema-object = ''
# sql.quoted-schema-object.escape = ''
# sql.constant = '#880000'
# sql.function = '#0000FF'
# sql.variable = '#19177C'
# sql.number = '#666666'
# sql.number.binary = ''
# sql.number.float = ''
# sql.number.hex = ''
# sql.number.integer = ''
# sql.operator = '#666666'
# sql.punctuation = ''
# sql.string = '#BA2121'
# sql.string.double-quouted = ''
# sql.string.escape = 'bold #BB6622'
# sql.string.single-quoted = ''
# sql.whitespace = ''
# Favorite queries.
[favorite_queries]
check = 'select "✔"'
# Use the -d option to reference a DSN.
# Special characters in passwords and other strings can be escaped with URL encoding.
[alias_dsn]
# example_dsn = mysql://[user[:password]@][host][:port][/dbname]

View file

@ -19,7 +19,7 @@ def test_ctor(refresher):
assert len(refresher.refreshers) > 0 assert len(refresher.refreshers) > 0
actual_handlers = list(refresher.refreshers.keys()) actual_handlers = list(refresher.refreshers.keys())
expected_handlers = ['databases', 'schemata', 'tables', 'users', 'functions', expected_handlers = ['databases', 'schemata', 'tables', 'users', 'functions',
'special_commands', 'show_commands'] 'special_commands', 'show_commands', 'keywords']
assert expected_handlers == actual_handlers assert expected_handlers == actual_handlers

View file

@ -21,7 +21,7 @@ def test_empty_string_completion(completer, complete_event):
result = list(completer.get_completions( result = list(completer.get_completions(
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list(map(Completion, sorted(completer.all_completions))) assert result == list(map(Completion, completer.all_completions))
def test_select_keyword_completion(completer, complete_event): def test_select_keyword_completion(completer, complete_event):
@ -39,9 +39,7 @@ def test_function_name_completion(completer, complete_event):
result = list(completer.get_completions( result = list(completer.get_completions(
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert sorted(x.text for x in result) == ["MASTER", "MAX"]
Completion(text='MASTER', start_position=-2),
Completion(text='MAX', start_position=-2)])
def test_column_name_completion(completer, complete_event): def test_column_name_completion(completer, complete_event):
@ -50,7 +48,7 @@ def test_column_name_completion(completer, complete_event):
result = list(completer.get_completions( result = list(completer.get_completions(
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list(map(Completion, sorted(completer.all_completions))) assert result == list(map(Completion, completer.all_completions))
def test_special_name_completion(completer, complete_event): def test_special_name_completion(completer, complete_event):

View file

@ -55,8 +55,8 @@ def test_empty_string_completion(completer, complete_event):
completer.get_completions( completer.get_completions(
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert list(map(Completion, sorted(completer.keywords) + assert list(map(Completion, completer.keywords +
sorted(completer.special_commands))) == result completer.special_commands)) == result
def test_select_keyword_completion(completer, complete_event): def test_select_keyword_completion(completer, complete_event):
@ -74,10 +74,10 @@ def test_table_completion(completer, complete_event):
result = completer.get_completions( result = completer.get_completions(
Document(text=text, cursor_position=position), complete_event) Document(text=text, cursor_position=position), complete_event)
assert list(result) == list([ assert list(result) == list([
Completion(text='`réveillé`', start_position=0),
Completion(text='`select`', start_position=0),
Completion(text='orders', start_position=0),
Completion(text='users', start_position=0), Completion(text='users', start_position=0),
Completion(text='orders', start_position=0),
Completion(text='`select`', start_position=0),
Completion(text='`réveillé`', start_position=0),
]) ])
@ -106,9 +106,9 @@ def test_suggested_column_names(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0), Completion(text='last_name', start_position=0),
] + ] +
list(map(Completion, completer.functions)) + list(map(Completion, completer.functions)) +
@ -132,9 +132,9 @@ def test_suggested_column_names_in_function(completer, complete_event):
complete_event) complete_event)
assert list(result) == list([ assert list(result) == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)]) Completion(text='last_name', start_position=0)])
@ -153,9 +153,9 @@ def test_suggested_column_names_with_table_dot(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)]) Completion(text='last_name', start_position=0)])
@ -174,9 +174,9 @@ def test_suggested_column_names_with_alias(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)]) Completion(text='last_name', start_position=0)])
@ -196,9 +196,9 @@ def test_suggested_multiple_column_names(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)] + Completion(text='last_name', start_position=0)] +
list(map(Completion, completer.functions)) + list(map(Completion, completer.functions)) +
[Completion(text='u', start_position=0)] + [Completion(text='u', start_position=0)] +
@ -221,9 +221,9 @@ def test_suggested_multiple_column_names_with_alias(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)]) Completion(text='last_name', start_position=0)])
@ -243,9 +243,9 @@ def test_suggested_multiple_column_names_with_dot(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='id', start_position=0),
Completion(text='email', start_position=0), Completion(text='email', start_position=0),
Completion(text='first_name', start_position=0), Completion(text='first_name', start_position=0),
Completion(text='id', start_position=0),
Completion(text='last_name', start_position=0)]) Completion(text='last_name', start_position=0)])
@ -256,8 +256,9 @@ def test_suggested_aliases_after_on(completer, complete_event):
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='u', start_position=0),
Completion(text='o', start_position=0), Completion(text='o', start_position=0),
Completion(text='u', start_position=0)]) ])
def test_suggested_aliases_after_on_right_side(completer, complete_event): def test_suggested_aliases_after_on_right_side(completer, complete_event):
@ -268,8 +269,9 @@ def test_suggested_aliases_after_on_right_side(completer, complete_event):
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='u', start_position=0),
Completion(text='o', start_position=0), Completion(text='o', start_position=0),
Completion(text='u', start_position=0)]) ])
def test_suggested_tables_after_on(completer, complete_event): def test_suggested_tables_after_on(completer, complete_event):
@ -279,8 +281,9 @@ def test_suggested_tables_after_on(completer, complete_event):
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='users', start_position=0),
Completion(text='orders', start_position=0), Completion(text='orders', start_position=0),
Completion(text='users', start_position=0)]) ])
def test_suggested_tables_after_on_right_side(completer, complete_event): def test_suggested_tables_after_on_right_side(completer, complete_event):
@ -291,8 +294,9 @@ def test_suggested_tables_after_on_right_side(completer, complete_event):
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='users', start_position=0),
Completion(text='orders', start_position=0), Completion(text='orders', start_position=0),
Completion(text='users', start_position=0)]) ])
def test_table_names_after_from(completer, complete_event): def test_table_names_after_from(completer, complete_event):
@ -302,10 +306,10 @@ def test_table_names_after_from(completer, complete_event):
Document(text=text, cursor_position=position), Document(text=text, cursor_position=position),
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='`réveillé`', start_position=0),
Completion(text='`select`', start_position=0),
Completion(text='orders', start_position=0),
Completion(text='users', start_position=0), Completion(text='users', start_position=0),
Completion(text='orders', start_position=0),
Completion(text='`select`', start_position=0),
Completion(text='`réveillé`', start_position=0),
]) ])
@ -317,12 +321,12 @@ def test_auto_escaped_col_names(completer, complete_event):
complete_event)) complete_event))
assert result == [ assert result == [
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='`ABC`', start_position=0),
Completion(text='`insert`', start_position=0),
Completion(text='id', start_position=0), Completion(text='id', start_position=0),
Completion(text='`insert`', start_position=0),
Completion(text='`ABC`', start_position=0),
] + \ ] + \
list(map(Completion, completer.functions)) + \ list(map(Completion, completer.functions)) + \
[Completion(text='`select`', start_position=0)] + \ [Completion(text='select', start_position=0)] + \
list(map(Completion, completer.keywords)) list(map(Completion, completer.keywords))
@ -334,9 +338,9 @@ def test_un_escaped_table_names(completer, complete_event):
complete_event)) complete_event))
assert result == list([ assert result == list([
Completion(text='*', start_position=0), Completion(text='*', start_position=0),
Completion(text='`ABC`', start_position=0),
Completion(text='`insert`', start_position=0),
Completion(text='id', start_position=0), Completion(text='id', start_position=0),
Completion(text='`insert`', start_position=0),
Completion(text='`ABC`', start_position=0),
] + ] +
list(map(Completion, completer.functions)) + list(map(Completion, completer.functions)) +
[Completion(text='réveillé', start_position=0)] + [Completion(text='réveillé', start_position=0)] +

View file

@ -276,7 +276,8 @@ def test_multiple_results(executor):
@pytest.mark.parametrize( @pytest.mark.parametrize(
'version_string, species, parsed_version_string, version', 'version_string, species, parsed_version_string, version',
( (
('5.7.25-TiDB-v6.1.0','TiDB', '5.7.25', 50725), ('5.7.25-TiDB-v6.1.0','TiDB', '6.1.0', 60100),
('8.0.11-TiDB-v7.2.0-alpha-69-g96e9e68daa', 'TiDB', '7.2.0', 70200),
('5.7.32-35', 'Percona', '5.7.32', 50732), ('5.7.32-35', 'Percona', '5.7.32', 50732),
('5.7.32-0ubuntu0.18.04.1', 'MySQL', '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), ('10.5.8-MariaDB-1:10.5.8+maria~focal', 'MariaDB', '10.5.8', 100508),

View file

@ -102,7 +102,7 @@ def test_sql_output(mycli):
mycli.formatter.query = "SELECT * FROM `table`" mycli.formatter.query = "SELECT * FROM `table`"
output = mycli.format_output(None, FakeCursor(), headers) output = mycli.format_output(None, FakeCursor(), headers)
assert "\n".join(output) == dedent('''\ assert "\n".join(output) == dedent('''\
INSERT INTO `table` (`letters`, `number`, `optional`, `float`, `binary`) VALUES INSERT INTO table (`letters`, `number`, `optional`, `float`, `binary`) VALUES
('abc', 1, NULL, 10.0e0, X'aa') ('abc', 1, NULL, 10.0e0, X'aa')
, ('d', 456, '1', 0.5e0, X'aabb') , ('d', 456, '1', 0.5e0, X'aabb')
;''') ;''')
@ -112,7 +112,7 @@ def test_sql_output(mycli):
mycli.formatter.query = "SELECT * FROM `database`.`table`" mycli.formatter.query = "SELECT * FROM `database`.`table`"
output = mycli.format_output(None, FakeCursor(), headers) output = mycli.format_output(None, FakeCursor(), headers)
assert "\n".join(output) == dedent('''\ assert "\n".join(output) == dedent('''\
INSERT INTO `database`.`table` (`letters`, `number`, `optional`, `float`, `binary`) VALUES INSERT INTO database.table (`letters`, `number`, `optional`, `float`, `binary`) VALUES
('abc', 1, NULL, 10.0e0, X'aa') ('abc', 1, NULL, 10.0e0, X'aa')
, ('d', 456, '1', 0.5e0, X'aabb') , ('d', 456, '1', 0.5e0, X'aabb')
;''') ;''')