diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 721f891..10c5140 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.9.4 +current_version = 0.9.7 files = SQLTools.py tag = True commit = True diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 9f24d4b..7f216c3 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,23 +1,30 @@ -> This is a guideline to help us to understand SQLTools Issues. +> This issue template helps us understand your SQLTools issues better. +> +> You don't need to stick to this template, but please try to guide us to reproduce the errors or understand your feature requests. > -> You don't need to stick to this, but please try to guide us to reproduce the errors or understand your feature requests. +> Before submitting an issue, please consider these things first: +> * Are you running the latest version? If not, try to upgrade. +> * Did you check the [Setup Guide](http://mtxr.github.io/SQLTools/)? +> * Did you check the logs in console (``Ctrl+` `` or select *View → Show Console*)? ### Issue Type -* [ ] Feature Request -* [ ] Bugfix/Errors -* [ ] Questions -* [ ] Other +Feature Request | +Bug/Error | +Question | +Other -### Prerequisites (For bugfixes) +### Description -* [ ] Are you running the latest version? -* [ ] Did you check the logs? -* [ ] Did you check the Setup? +[Description of the bug / feature / question] -### Description +### Version + +- *SQLTools Version*: vX.Y.Z +- *OS*: (Windows, Mac, Linux) +- *RDBMS*: (MySQL, PostgreSQL, Oracle, MSSQL, SQLite, Vertica, ...) -[Description of the bug or feature] +> You can get this information by executing `ST: About` from Sublime `Command Palette`. ### Steps to Reproduce (For bugfixes) @@ -28,11 +35,3 @@ **Expected behavior:** [What you expected to happen] **Actual behavior:** [What actually happened] - -### Versions - -- *Version*: vX.Y.Z -- *OS*: ... -- *RDBMS*: (MySQL, PostgreSQL, Oracle, MSSQL, SQLite, Vertica, ...) - -You can get this information from executing `ST: About` from Sublime `Command Palette`. diff --git a/SQLTools.py b/SQLTools.py index 632bb24..152c35e 100644 --- a/SQLTools.py +++ b/SQLTools.py @@ -1,4 +1,4 @@ -__version__ = "v0.9.4" +__version__ = "v0.9.7" import sys import os @@ -57,9 +57,21 @@ def startPlugin(): QUERIES_FILENAME = os.path.join(USER_FOLDER, SQLTOOLS_QUERIES_FILE) QUERIES_FILENAME_DEFAULT = os.path.join(DEFAULT_FOLDER, SQLTOOLS_QUERIES_FILE) - settings = Settings(SETTINGS_FILENAME, default=SETTINGS_FILENAME_DEFAULT) + try: + settings = Settings(SETTINGS_FILENAME, default=SETTINGS_FILENAME_DEFAULT) + except Exception as e: + msg = __package__ + ": Failed to parse " + SQLTOOLS_SETTINGS_FILE + " file" + print(msg + "\nError: " + str(e)) + Window().status_message(msg) + + try: + connections = Settings(CONNECTIONS_FILENAME, default=CONNECTIONS_FILENAME_DEFAULT) + except Exception as e: + msg = __package__ + ": Failed to parse " + SQLTOOLS_CONNECTIONS_FILE + " file" + print(msg + "\nError: " + str(e)) + Window().status_message(msg) + queries = Storage(QUERIES_FILENAME, default=QUERIES_FILENAME_DEFAULT) - connections = Settings(CONNECTIONS_FILENAME, default=CONNECTIONS_FILENAME_DEFAULT) history = History(settings.get('history_size', 100)) Logger.setPackageVersion(__version__) @@ -356,7 +368,7 @@ def on_query_completions(view, prefix, locations): lineStartToLocation = sublime.Region(lineStartPoint, currentPoint) try: lineStr = view.substr(lineStartToLocation) - prefix = re.split('[^`\"\w.]+', lineStr).pop() + prefix = re.split('[^`\"\w.\$]+', lineStr).pop() except Exception as e: Log(e) diff --git a/SQLTools.sublime-settings b/SQLTools.sublime-settings index 154adac..02982c6 100644 --- a/SQLTools.sublime-settings +++ b/SQLTools.sublime-settings @@ -74,7 +74,7 @@ }, "queries": { "desc" : { - "query": "select '|' || quote_ident(table_schema)||'.'||quote_ident(table_name) ||'|' as tblname from information_schema.tables where table_schema = any(current_schemas(false)) and table_schema not in ('pg_catalog', 'information_schema') order by table_schema = current_schema() desc, table_schema, table_name", + "query": "select '|' || quote_ident(table_schema)||'.'||quote_ident(table_name) ||'|' as tblname from information_schema.tables where table_schema not in ('pg_catalog', 'information_schema') order by table_schema = current_schema() desc, table_schema, table_name", "options": ["--tuples-only", "--no-psqlrc"] }, "desc table": { @@ -86,11 +86,11 @@ "options": ["--no-password"] }, "columns": { - "query": "select '|' || quote_ident(table_name) || '.' || quote_ident(column_name) || '|' from information_schema.columns where table_schema = any(current_schemas(false)) and table_schema not in ('pg_catalog', 'information_schema') order by table_name, ordinal_position", + "query": "select '|' || quote_ident(table_name) || '.' || quote_ident(column_name) || '|' from information_schema.columns where table_schema not in ('pg_catalog', 'information_schema') order by table_name, ordinal_position", "options": ["--no-password", "--tuples-only", "--no-psqlrc"] }, "functions": { - "query": "select '|' || quote_ident(n.nspname)||'.'||quote_ident(f.proname) || '(' || pg_get_function_identity_arguments(f.oid) || ')' || '|' as funname from pg_catalog.pg_proc as f inner join pg_catalog.pg_namespace as n on n.oid = f.pronamespace where f.proisagg = false and n.nspname = any(current_schemas(false)) and n.nspname not in ('pg_catalog', 'information_schema')", + "query": "select '|' || quote_ident(n.nspname)||'.'||quote_ident(f.proname) || '(' || pg_get_function_identity_arguments(f.oid) || ')' || '|' as funname from pg_catalog.pg_proc as f inner join pg_catalog.pg_namespace as n on n.oid = f.pronamespace where f.proisagg = false and n.nspname not in ('pg_catalog', 'information_schema')", "options": ["--no-password", "--tuples-only", "--no-psqlrc"] }, "desc function": { @@ -157,7 +157,7 @@ "args_optional": ["--login-path=\"{login-path}\"", "--defaults-extra-file=\"{defaults-extra-file}\"", "-p\"{password}\""], "queries": { "desc" : { - "query": "select concat('|', table_schema, '.', table_name, '|') from information_schema.tables where table_schema = database() order by table_name;", + "query": "select concat('|', case when table_schema REGEXP '[^0-9a-zA-Z$_]' then concat('`',table_schema,'`') else table_schema end, '.', case when table_name REGEXP '[^0-9a-zA-Z$_]' then concat('`',table_name,'`') else table_name end, '|') from information_schema.tables where table_schema = database() order by table_name;", "options": ["-f", "--silent", "--raw"] }, "desc table": { @@ -169,15 +169,15 @@ "options": ["-f", "--table"] }, "columns": { - "query": "select concat('|', table_name, '.', column_name, '|') from information_schema.columns where table_schema = database() order by table_name, ordinal_position;", + "query": "select concat('|', case when table_name REGEXP '[^0-9a-zA-Z$_]' then concat('`',table_name,'`') else table_name end, '.', case when column_name REGEXP '[^0-9a-zA-Z$_]' then concat('`',column_name,'`') else column_name end, '|') from information_schema.columns where table_schema = database() order by table_name, ordinal_position;", "options": ["-f", "--silent", "--raw"] }, "functions": { - "query": "select concat('|', routine_schema, '.', routine_name, '()', '|') from information_schema.routines where routine_schema = database();", + "query": "select concat('|', case when routine_schema REGEXP '[^0-9a-zA-Z$_]' then concat('`',routine_schema,'`') else routine_schema end, '.', case when routine_name REGEXP '[^0-9a-zA-Z$_]' then concat('`',routine_name,'`') else routine_name end, '()', '|') from information_schema.routines where routine_schema = database();", "options": ["-f", "--silent", "--raw"] }, "desc function": { - "query": "select routine_definition from information_schema.routines where concat(routine_schema, '.', routine_name) = '%s';", + "query": "select routine_definition from information_schema.routines where concat(case when routine_schema REGEXP '[^0-9a-zA-Z$_]' then concat('`',routine_schema,'`') else routine_schema end, '.', case when routine_name REGEXP '[^0-9a-zA-Z$_]' then concat('`',routine_name,'`') else routine_name end) = '%s';", "options": ["-f", "--silent", "--raw"] }, "explain plan": { diff --git a/SQLToolsAPI/Completion.py b/SQLToolsAPI/Completion.py index d9a5231..0a1b43d 100644 --- a/SQLToolsAPI/Completion.py +++ b/SQLToolsAPI/Completion.py @@ -39,6 +39,11 @@ def _stripPrefix(text, prefix): return text +# escape $ sign when formatting output +def _escapeDollarSign(ident): + return ident.replace("$", "\$") + + class CompletionItem(namedtuple('CompletionItem', ['type', 'ident'])): """ Represents a potential or actual completion item. @@ -149,10 +154,10 @@ def format(self, stripQuotes=False): part = self.ident.split('.') if len(part) > 1: return ("{0}\t({1} {2})".format(part[1], part[0], typeDisplay), - _stripQuotesOnDemand(part[1], stripQuotes)) + _stripQuotesOnDemand(_escapeDollarSign(part[1]), stripQuotes)) return ("{0}\t({1})".format(self.ident, typeDisplay), - _stripQuotesOnDemand(self.ident, stripQuotes)) + _stripQuotesOnDemand(_escapeDollarSign(self.ident), stripQuotes)) class Completion: @@ -381,7 +386,7 @@ def _singleDotCompletions(self, prefix, identifiers, joinAlias=None): # we use set, as we are interested only in unique identifiers for ident in identifiers: - if ident.has_alias() and ident.alias == prefixParent: + if ident.has_alias() and ident.alias.lower() == prefixParent: if ident.is_query_alias: sqlQueryAliases.add(ident.alias) diff --git a/messages.json b/messages.json index 278f11b..20f4834 100644 --- a/messages.json +++ b/messages.json @@ -9,5 +9,8 @@ "0.9.1": "messages/v0.9.1.md", "0.9.2": "messages/v0.9.2.md", "0.9.3": "messages/v0.9.3.md", - "0.9.4": "messages/v0.9.4.md" + "0.9.4": "messages/v0.9.4.md", + "0.9.5": "messages/v0.9.5.md", + "0.9.6": "messages/v0.9.6.md", + "0.9.7": "messages/v0.9.7.md" } diff --git a/messages/v0.9.5.md b/messages/v0.9.5.md new file mode 100644 index 0000000..0e50ac6 --- /dev/null +++ b/messages/v0.9.5.md @@ -0,0 +1,12 @@ +## v0.9.5 Notes + +### Improvements + +* New Feature: List and Insert Saved Queries (ctrl+e ctrl+i) [#126] +* Better error messages if setting json file could not be parsed + +### Fixes + +* Display completions for upper case aliases [#142] +* Fix the display of status bar message when query is executed [#130] +* Open Saved Queries executed the query if not connected to a database prior [#125] diff --git a/messages/v0.9.6.md b/messages/v0.9.6.md new file mode 100644 index 0000000..f975efa --- /dev/null +++ b/messages/v0.9.6.md @@ -0,0 +1,5 @@ +## v0.9.6 Notes + +### Fixes + +* [MySQL] Added basic backtick escaping of identifiers [#147] diff --git a/messages/v0.9.7.md b/messages/v0.9.7.md new file mode 100644 index 0000000..f38adb4 --- /dev/null +++ b/messages/v0.9.7.md @@ -0,0 +1,5 @@ +## v0.9.7 Notes + +### Fixes + +* Completions not working with identifiers containing $ symbol [#152]