gh-133390: Support table, index, trigger, view, column, function, and schema completion in the sqlite3 CLI #136101
+163
−13
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
It is not until recently that I found SQLite has a completion extension, which can potentially be used to provide candidates for the CPython sqlite3 CLI. But the CPython
sqlite3
module is not built with loadable extension support by default. So, we still have to implement completion on our own. This PR refers to the implementation of SQLite's completion extension. The completion in both SQLite's implementation and this PR is not context-aware. It simply lists all possible candidates that match the user's input as a prefix.Tables, indexes, triggers, and views
These candidates are retrieved using
PRAGMA database_list
. Thedatabase_list
command is available since at least 2003, thus it should be OK to be used as CPython requires SQLite>=3.15.2 (2016-11-28).Columns
Column candidate access is done with a SQL statement copied from SQLite's implementation. It uses PRAGMA table-valued function (available since SQLite 3.16.0). On SQLite<3.16.0, column completion are skipped.
Functions
Function candidates are retrieved using PRAGMA
function_list
. Thefunction_list
command is available since SQLite v3.30.0, newer than v3.15.2 that CPython requires. On SQLite<3.30.0, function completion will be skipped. Some SQL functions may have multiple rows in the result set if they can be called with a variable number of arguments, so theDISTINCT
keyword is used to remove duplicates.The result of
PRAGMA function_list
contains two items that are not alphabetical:->
and->>
. These two are excluded from complication list in this PR. Readline considers-
and>
as word break and passestext
as an empty string to_complete()
when the cursor is at the right hand side of-
or>
. This means that even if we include->
and->>
in the candidate list, they'll never be auto-completed. To make Readline recognize them as valid prefixes, we'd need to modify rl_special_prefixes, but I didn't find an API in CPython to do this. As->
and->>
are short and not difficult to type, I suppose excluding them is OK.Duplication and sorting
GNU Readline ignores duplicates and sorts candidates by default. To make sure the completion is consistent even without Readline's guard, I drop duplicates (if any) and sort candidates (by
_completion_matches = sorted(set(_completion_matches))
) in this PR as well, but if it looks unnecessary I can remove it.Tests
Some settings are added in
write_input()
to turn off Readline's pager and multi-column layout, making it easier to parse candidates intest_complete_columns()
,test_complete_table_indexes_triggers_views()
, andtest_complete_schemata()
.