o
    8Dik;                     @  s  d dl mZ d dlZd dlmZ d dlmZ d dl	m
Z
mZ d dlmZmZ ejr8d dlmZ ejejejf Zd1d2ddZeejjh d ZejejejejejfZ d1d2ddZ!d1d2ddZ"d3ddZ#d4dd Z$d5d#d$Z%d6d%d&Z&d4d'd(Z'd6d)d*Z(d7d+d,Z)d7d-d.Z*d8d/d0Z+dS )9    )annotationsN)defaultdict)expressions)find_new_nameseq_get)Scopetraverse_scope)EF
expressionr	   leave_tables_isolatedboolreturnc                 C  s   t | |} t| |} | S )a  
    Rewrite sqlglot AST to merge derived tables into the outer query.

    This also merges CTEs if they are selected from only once.

    Example:
        >>> import sqlglot
        >>> expression = sqlglot.parse_one("SELECT a FROM (SELECT x.a FROM x) CROSS JOIN y")
        >>> merge_subqueries(expression).sql()
        'SELECT x.a FROM x CROSS JOIN y'

    If `leave_tables_isolated` is True, this will not merge inner queries into outer
    queries if it would result in multiple table selects in a single query:
        >>> expression = sqlglot.parse_one("SELECT a FROM (SELECT x.a FROM x) CROSS JOIN y")
        >>> merge_subqueries(expression, leave_tables_isolated=True).sql()
        'SELECT a FROM (SELECT x.a FROM x) CROSS JOIN y'

    Inspired by https://dev.mysql.com/doc/refman/8.0/en/derived-table-optimization.html

    Args:
        expression (sqlglot.Expression): expression to optimize
        leave_tables_isolated (bool):
    Returns:
        sqlglot.Expression: optimized expression
    )
merge_ctesmerge_derived_tables)r
   r    r   [/var/www/Datamplify/venv/lib/python3.10/site-packages/sqlglot/optimizer/merge_subqueries.pymerge_subqueries   s   

r   >   fromhintjoinsorderwherer   c           
      C  s  t | }tt}|D ] }|j D ]\}}t|tr)|jr)|t| 	|||f qq
dd |
 D }|D ]H\}}}|tjtj}t||||r~|j}	t|||	 t||||	 t|||	 t|| t||| t||| t|| t| |  q6| S )Nc                 S  s$   g | ]\}}t |d kr|d qS )   r   )len).0kvr   r   r   
<listcomp>W   s   $ zmerge_ctes.<locals>.<listcomp>)r   r   listselected_sourcesvalues
isinstancer   is_cteidappenditemsfind_ancestorexpFromJoin
_mergeablealias_or_name_rename_inner_sources_merge_from_merge_expressions_merge_order_merge_joins_merge_where_merge_hints_pop_cteclear_cache)
r
   r   scopescte_selectionsouter_scopetableinner_scopesingular_cte_selectionsfrom_or_joinaliasr   r   r   r   F   s:   


r   c                 C  s   t | D ]L}|jD ]F}|tjtj}|j}|j| }t||||rOt	||| t
|||| t||| t|| t||| t||| t|| |  q	q| S N)r   derived_tablesr&   r'   r(   r)   r+   sourcesr*   r,   r-   r.   r/   r0   r1   r2   r4   )r
   r   r7   subqueryr;   r<   r9   r   r   r   r   h   s"   



r   r7   r   r9   r;   
FromOrJoinc                   sR  j   fdd} fdd}fdd}tj tjoj j ottjotfddtD  oj	d	d
uoj
 otdd jD  o|oXtjdk ot tjojj	doj jdv  ot tjoj	dotdd j j	dg D  o|  o|  o|  oj	doj ottjdtj S )zG
    Return True if `inner_select` can be merged into outer query.
    c                    sB   dd j D j dd jD }  fdd| D }t|S )Nc                 S  s   h | ]}| tjr|jqS r   )findr'   Windowr+   r   sr   r   r   	<setcomp>   s    zV_mergeable.<locals>._is_a_window_expression_in_unmergable_operation.<locals>.<setcomp>c              
   S  s0   g | ]}| tjtjtjtjtjtjr|qS r   )r&   r'   WhereGroupOrderr)   HavingAggFuncr   columnr   r   r   r      s    zW_mergeable.<locals>._is_a_window_expression_in_unmergable_operation.<locals>.<listcomp>c                   s$   g | ]}|j  kr|jv r|qS r   r8   namerL   inner_select_namewindow_aliasesr   r   r      s
    )selectsr+   columnsany)unmergable_window_columns window_expressions_in_unmergable)r;   inner_selectr7   rP   r   /_is_a_window_expression_in_unmergable_operation   s   zC_mergeable.<locals>._is_a_window_expression_in_unmergable_operationc                    s   t tjsdS j jd} | sdS  fdd| tjD }jjd}|s-dS |jdd jj	D t
fdd	|D S )
a  
        All columns from the inner select in the ON clause must be from the first FROM table.

        That is, this can be merged:
            SELECT * FROM x JOIN (SELECT y.a AS a FROM y JOIN z) AS q ON x.a = q.a
                                         ^^^           ^
        But this can't:
            SELECT * FROM x JOIN (SELECT z.a AS a FROM y JOIN z) AS q ON x.a = q.a
                                         ^^^                  ^
        Fonc                   s   g | ]
}|j  kr|jqS r   rN   )r   c)r<   r   r   r      s    zP_mergeable.<locals>._outer_select_joins_on_inner_select_join.<locals>.<listcomp>r   c                 S  s   i | ]}|j |qS r   )r+   rD   r   r   r   
<dictcomp>   s    zP_mergeable.<locals>._outer_select_joins_on_inner_select_join.<locals>.<dictcomp>c                 3  s0    | ]}|  tjD ]}|j kV  qqd S r=   )find_allr'   Columnr8   )r   	selectioncol)inner_from_tableinner_projectionsr   r   	<genexpr>   s    zO_mergeable.<locals>._outer_select_joins_on_inner_select_join.<locals>.<genexpr>)r!   r'   r)   r+   argsgetr]   r^   r
   rS   rU   )rZ   
selections
inner_from)r;   r9   )r<   ra   rb   r   (_outer_select_joins_on_inner_select_join   s   z<_mergeable.<locals>._outer_select_joins_on_inner_select_joinc                    s.    j j} j j}|r|| u rdS |j}|s
dS )NTF)r
   parent)ctenode)r9   r7   r   r   _is_recursive   s   z!_mergeable.<locals>._is_recursivec                 3  s    | ]	} j |V  qd S r=   )rd   re   r   arg)rX   r   r   rc          z_mergeable.<locals>.<genexpr>r   Nc                 s  s$    | ]}| tjtjtjV  qd S r=   )rB   r'   rK   SelectExplode)r   er   r   r   rc      s   " r   r   )FULLLEFTRIGHTc                 s  s    | ]}|j d v V  qdS ))rs   ru   N)side)r   jr   r   r   rc      s    

r   r   r   )r
   unnestr!   r'   rp   is_starrU   UNMERGABLE_ARGSrd   re   pivotsr   r   r   r)   rv   r(   is_unionr   QueryTransform)r7   r9   r   r;   rY   rh   rl   r   )r;   r9   rX   r7   r   r*   {   sV   

	

r*   r<   strNonec                 C  s   t |j}t | j}||}||h8 }||}|D ]\}t||}|j| \}	}
t|}t|	tjr>|	j	r>|	 d| n"t|	tjrN|	
t|	| nt|	jtjr`|	j dtj|d ||D ]}| dt| qe||| qdS )z]
    Renames any sources in the inner query that conflict with names in the outer query.
    r<   )thisr8   N)setr   intersectionunionr   r'   to_identifierr!   Tabler<   replacealias_ri   Subquery
TableAliassource_columnsrename_source)r7   r9   r<   inner_takenouter_taken	conflictstakenconflictnew_namesource_	new_aliasrM   r   r   r   r,      s&   






r,   node_to_replace t.Union[exp.Subquery, exp.Table]c                 C  s   |j jd j}|d|jd || | jD ]}|tj	}|D ]}|j
|j
kr5|dt|j
 q#q| | | |j
|j|j
  dS )z<
    Merge FROM clause of inner query into outer query.
    r   r   r   N)r
   rd   r   r   re   r   
join_hintsr]   r'   r   r+   r   remove_source
add_sourcer?   )r7   r9   r   r<   new_subquery	join_hinttablesr8   r   r   r   r-      s   	


r-   c                 C  s   g }|j jdp
g }|D ]}|| | |j|j|j  q|rI| j jdg }t|tj	r3d}n|
|d }||||< | j d| dS dS )z=
    Merge JOIN clauses of inner query into outer query.
    r   r   r   N)r
   rd   re   r$   r   r+   r?   r!   r'   r(   indexr   )r7   r9   r;   	new_joinsr   joinouter_joinspositionr   r   r   r0     s   
r0   c           	      C  s   t t}| jD ]}|j|kr||j | q|jjD ]7}|j}|s#q|	|g }|
 }t|t }|D ]}t|jtjtjfrJ|rJtj|dd}||  q5qdS )z
    Merge projections of inner query into outer query.

    Args:
        outer_scope (sqlglot.optimizer.scope.Scope)
        inner_scope (sqlglot.optimizer.scope.Scope)
        alias (str)
    FcopyN)r   r   rT   r8   rO   r$   r
   r   r+   re   unaliasr!   SAFE_TO_REPLACE_UNWRAPPEDri   r'   UnaryBinaryparenr   r   )	r7   r9   r<   outer_columnsrM   r
   projection_namecolumns_to_replacemust_wrap_expressionr   r   r   r.   .  s$   


r.   c           	      C  s   |j jd}|r|jsdS | j }t|tjrY|jd}|r#|jhnt }|jd D ]}|j}|	| ||jkr< nq+t
|j|krY|j|jdd |d|jd dS |j|jdd dS )z
    Merge WHERE clause of inner query into outer query.

    Args:
        outer_scope (sqlglot.optimizer.scope.Scope)
        inner_scope (sqlglot.optimizer.scope.Scope)
        from_or_join (exp.From|exp.Join)
    r   Nr   r   Fr   rZ   )r
   rd   re   r   r!   r'   r)   r+   r   addcolumn_table_namesrZ   r   )	r7   r9   r;   r   r
   from_r?   r   r   r   r   r   r1   P  s$   	


r1   c                   sZ   t  fdddD st jdkst dd  jjD rdS  jd|jjd dS )z
    Merge ORDER clause of inner query into outer query.

    Args:
        outer_scope (sqlglot.optimizer.scope.Scope)
        inner_scope (sqlglot.optimizer.scope.Scope)
    c                 3  s    | ]
} j j|V  qd S r=   )r
   rd   re   rm   r7   r   r   rc   |  s    
z_merge_order.<locals>.<genexpr>)groupdistincthavingr   r   c                 s  s    | ]	}| tjV  qd S r=   )rB   r'   rK   )r   r
   r   r   r   rc     ro   Nr   )rU   r   r   r
   r   r   rd   re   )r7   r9   r   r   r   r/   s  s   	r/   c                 C  sV   |j jd}|sd S | j jd}|r"|jD ]}|d| qd S | j d| d S )Nr   r   )r
   rd   re   r   r$   r   )r7   r9   inner_scope_hintouter_scope_hinthint_expressionr   r   r   r2     s   
r2   c                 C  s4   | j j}|j}t|jdkr|  dS |  dS )za
    Remove CTE from the AST.

    Args:
        inner_scope (sqlglot.optimizer.scope.Scope)
    r   N)r
   ri   r   r   pop)r9   rj   with_r   r   r   r3     s
   r3   )F)r
   r	   r   r   r   r	   )
r7   r   r9   r   r   r   r;   rA   r   r   )r7   r   r9   r   r<   r~   r   r   )
r7   r   r9   r   r   r   r<   r~   r   r   )r7   r   r9   r   r;   rA   r   r   )r7   r   r9   r   r   r   )r9   r   r   r   ),
__future__r   typingtcollectionsr   sqlglotr   r'   sqlglot.helperr   r   sqlglot.optimizer.scoper   r   TYPE_CHECKINGsqlglot._typingr	   Unionr(   r)   rA   r   r   rp   	arg_typesrz   r^   EQFuncNEQParenr   r   r   r*   r,   r-   r0   r.   r1   r/   r2   r3   r   r   r   r   <module>   s8     	"

e



"
#
