@@ -21,7 +21,7 @@ class TableInfo:
2121 sub_select : ast .ASTNode = None
2222 predictor_info : dict = None
2323 join_condition = None
24-
24+ index : int = None
2525
2626class PlanJoin :
2727
@@ -85,12 +85,15 @@ def __init__(self, planner):
8585
8686 # index to lookup tables
8787 self .tables_idx = None
88+ self .tables = []
89+ self .tables_fetch_step = {}
8890
8991 self .step_stack = None
9092 self .query_context = {}
9193
9294 self .partition = None
9395
96+
9497 def plan (self , query ):
9598 self .tables_idx = {}
9699 join_step = self .plan_join_tables (query )
@@ -146,7 +149,8 @@ def resolve_table(self, table):
146149 return TableInfo (integration , table , aliases , conditions = [], sub_select = sub_select )
147150
148151 def get_table_for_column (self , column : Identifier ):
149-
152+ if not isinstance (column , Identifier ):
153+ return
150154 # to lowercase
151155 parts = tuple (map (str .lower , column .parts [:- 1 ]))
152156 if parts in self .tables_idx :
@@ -161,6 +165,9 @@ def get_join_sequence(self, node, condition=None):
161165 for alias in table_info .aliases :
162166 self .tables_idx [alias ] = table_info
163167
168+ table_info .index = len (self .tables )
169+ self .tables .append (table_info )
170+
164171 table_info .predictor_info = self .planner .get_predictor (node )
165172
166173 if condition is not None :
@@ -378,13 +385,16 @@ def process_table(self, item, query_in):
378385 # not use conditions
379386 conditions = []
380387
388+ conditions += self .get_filters_from_join_conditions (item )
389+
381390 if self .query_context ['use_limit' ]:
382391 order_by = None
383392 if query_in .order_by is not None :
384393 order_by = []
385394 # all order column be from this table
386395 for col in query_in .order_by :
387- if self .get_table_for_column (col .field ).table != item .table :
396+ table_info = self .get_table_for_column (col .field )
397+ if table_info is None or table_info .table != item .table :
388398 order_by = False
389399 break
390400 col = copy .deepcopy (col )
@@ -408,6 +418,8 @@ def process_table(self, item, query_in):
408418 query2 .where = cond
409419
410420 step = self .planner .get_integration_select_step (query2 )
421+ self .tables_fetch_step [item .index ] = step
422+
411423 self .add_plan_step (step )
412424 self .step_stack .append (step )
413425
@@ -442,6 +454,70 @@ def _check_conditions(node, **kwargs):
442454 query_traversal (model_table .join_condition , _check_conditions )
443455 return columns_map
444456
457+ def get_filters_from_join_conditions (self , fetch_table ):
458+
459+ binary_ops = set ()
460+ conditions = []
461+ data_conditions = []
462+
463+ def _check_conditions (node , ** kwargs ):
464+ if not isinstance (node , BinaryOperation ):
465+ return
466+
467+ if node .op != '=' :
468+ binary_ops .add (node .op .lower ())
469+ return
470+
471+ arg1 , arg2 = node .args
472+ table1 = self .get_table_for_column (arg1 ) if isinstance (arg1 , Identifier ) else None
473+ table2 = self .get_table_for_column (arg2 ) if isinstance (arg2 , Identifier ) else None
474+
475+ if table1 is not fetch_table :
476+ if table2 is not fetch_table :
477+ return
478+ # set our table first
479+ table1 , table2 = table2 , table1
480+ arg1 , arg2 = arg2 , arg1
481+
482+ if isinstance (arg2 , Constant ):
483+ conditions .append (node )
484+ elif table2 is not None :
485+ data_conditions .append ([arg1 , arg2 ])
486+
487+ query_traversal (fetch_table .join_condition , _check_conditions )
488+
489+ binary_ops .discard ('and' )
490+ if len (binary_ops ) > 0 :
491+ # other operations exists, skip
492+ return []
493+
494+ for arg1 , arg2 in data_conditions :
495+ # is fetched?
496+ table2 = self .get_table_for_column (arg2 )
497+ fetch_step = self .tables_fetch_step .get (table2 .index )
498+
499+ if fetch_step is None :
500+ continue
501+
502+ # extract distinct values
503+ # remove aliases
504+ arg1 = Identifier (parts = [arg1 .parts [- 1 ]])
505+ arg2 = Identifier (parts = [arg2 .parts [- 1 ]])
506+
507+ query2 = Select (targets = [arg2 ], distinct = True )
508+ subselect_step = SubSelectStep (query2 , fetch_step .result )
509+ subselect_step = self .add_plan_step (subselect_step )
510+
511+ conditions .append (BinaryOperation (
512+ op = 'in' ,
513+ args = [
514+ arg1 ,
515+ Parameter (subselect_step .result )
516+ ]
517+ ))
518+
519+ return conditions
520+
445521 def process_predictor (self , item , query_in ):
446522 if len (self .step_stack ) == 0 :
447523 raise NotImplementedError ("Predictor can't be first element of join syntax" )
0 commit comments