@@ -445,6 +445,7 @@ class SQLWidget(QTextEdit):
445445 "LIMIT" , "OFFSET" , "UNION" , "ALL" ,
446446 "VALUES" , "SET" , "CASE" , "WHEN" , "THEN" , "ELSE" , "END"
447447 ]
448+ SQL_KEYWORDS_SET = set (SQL_KEYWORDS )
448449
449450 def __init__ (self , editor_window ):
450451 import polars as pl
@@ -477,15 +478,42 @@ def __init__(self, editor_window):
477478 self .sql_context = pl .SQLContext (eager = False )
478479 self .update_completer_options ({})
479480
480- def update_completer_options (self , data , selected = None ):
481- data = self ._filter_data_for_sql (data )
482- if selected is not None and self ._handled_by_polars_sql (selected ):
483- data ['self' ] = selected
484- col_names = selected .collect_schema ().names ()
481+ def update_completer_options (self , data = None , selected = None ):
482+ if data is not None :
483+ data = self ._filter_data_for_sql (data )
484+ if selected is not None and self ._handled_by_polars_sql (selected ):
485+ data ['self' ] = selected
486+ self .data = data
487+ self .sql_context .register_many (data )
485488 else :
486- col_names = []
487- self .sql_context .register_many (data )
489+ data = self .data
490+
491+ if 'self' in data :
492+ table_names_to_fetch_columns = ['self' ]
493+ else :
494+ table_names_to_fetch_columns = []
495+
488496 table_names = [k for k , v in data .items ()]
497+
498+ # extract table names from the current FROM clause
499+ query_text = self .toPlainText ()
500+ m = re .search (r'\s+FROM\s+(\S+)' , query_text , re .IGNORECASE )
501+ if m :
502+ after_from = m .group (1 )
503+ # try any identifier found in the query after the FROM keyword
504+ # there will probably be false positives if a column has the same
505+ # name as another table but that should be rare
506+ from_tables = [word for word in after_from .split ()
507+ if word not in self .SQL_KEYWORDS_SET and word in data ]
508+ if from_tables :
509+ table_names_to_fetch_columns = from_tables
510+
511+ # add column names from all the used tables or self, if present
512+ col_names_set = set ()
513+ for table_name in table_names_to_fetch_columns :
514+ col_names_set .update (set (data [table_name ].collect_schema ().names ()))
515+ col_names = sorted (col_names_set )
516+
489517 logger .debug (f"available tables for SQL queries: { table_names } " )
490518 logger .debug (f"available columns for SQL queries: { col_names } " )
491519 completions = table_names + col_names + self .SQL_KEYWORDS
@@ -520,6 +548,7 @@ def insert_completion(self, completion):
520548 at_end = cursor .position () == len (self .toPlainText ())
521549 cursor .insertText (completion + (' ' if at_end else '' ))
522550 self .setTextCursor (cursor )
551+ self .update_completer_options ()
523552
524553 def keyPressEvent (self , event ):
525554 completer_popup = self .completer .popup ()
@@ -574,14 +603,17 @@ def keyPressEvent(self, event):
574603 self .clear ()
575604 return
576605 super ().keyPressEvent (event )
606+ self .update_completer_options ()
577607 # we need to compute the prefix *after* the keypress event has been
578- # handled so that the prefix contains the last key stroke
608+ # handled so that the prefix contains the last keystroke
579609 prefix = self .get_word_prefix ()
580610 if prefix :
581611 self .completer .setCompletionPrefix (prefix )
582612 num_completion = self .completer .completionCount ()
583- if (0 < num_completion <= self .completer .maxVisibleItems () and
584- not completer_popup .isVisible ()):
613+ # we must show the popup even if it is already visible, because
614+ # the number of completions might have changed and the popup size
615+ # needs to be updated
616+ if 0 < num_completion <= self .completer .maxVisibleItems ():
585617 self .show_autocomplete_popup ()
586618 elif num_completion == 0 and completer_popup .isVisible ():
587619 completer_popup .hide ()
@@ -625,6 +657,7 @@ def search_and_recall_history(self, direction: int):
625657 if self .history [index ].startswith (prefix ):
626658 self .history_index = index
627659 self .setPlainText (self .history [self .history_index ])
660+ self .update_completer_options ()
628661 cursor .setPosition (cursor_pos )
629662 self .setTextCursor (cursor )
630663 return True
0 commit comments