4949 visitors ,
5050)
5151from sqlalchemy .sql .expression import Join
52+ from sqlalchemy .sql .selectable import CompoundSelect , Select
5253
5354if TYPE_CHECKING :
5455 from collections .abc import Callable , MutableMapping
@@ -288,6 +289,28 @@ def _reject_correlated_subquery(self, inner: Any) -> None:
288289 "Excel dialect does not support correlated subqueries"
289290 )
290291
292+ @staticmethod
293+ def _guard_subquery_shape (inner : Select [Any ] | CompoundSelect [Any ]) -> None :
294+ if isinstance (inner , CompoundSelect ):
295+ raise exc .CompileError (
296+ "Excel dialect does not support compound subqueries in WHERE ... IN"
297+ )
298+
299+ if len (inner .selected_columns ) != 1 :
300+ raise exc .CompileError (
301+ "Excel dialect only supports single-column subqueries in WHERE ... IN"
302+ )
303+
304+ if inner ._order_by_clauses :
305+ raise exc .CompileError (
306+ "Excel dialect does not support ORDER BY in subqueries"
307+ )
308+
309+ if inner ._limit_clause is not None or inner ._offset_clause is not None :
310+ raise exc .CompileError (
311+ "Excel dialect does not support LIMIT/OFFSET in subqueries"
312+ )
313+
291314 def _is_unresolved_bindparam (self , bindparam : elements .BindParameter [Any ]) -> bool :
292315 return bool (getattr (bindparam , "required" , False )) and (
293316 getattr (bindparam , "callable" , None ) is None
@@ -580,13 +603,18 @@ def visit_subquery(self, subquery: Any, **kw: Any) -> str:
580603
581604 inner = getattr (subquery , "element" , None )
582605 if inner is not None :
583- # Reject subqueries that themselves contain a JOIN
584- for from_clause in inner .get_final_froms ():
585- if isinstance (from_clause , Join ):
586- raise exc .CompileError (
587- "Excel dialect does not support JOIN inside subqueries"
588- )
589- self ._reject_correlated_subquery (inner )
606+ if isinstance (inner , CompoundSelect ):
607+ self ._guard_subquery_shape (inner )
608+ elif getattr (inner , "__visit_name__" , None ) == "select" :
609+ select_inner = cast ("Select[Any]" , inner )
610+ self ._guard_subquery_shape (select_inner )
611+ # Reject subqueries that themselves contain a JOIN
612+ for from_clause in select_inner .get_final_froms ():
613+ if isinstance (from_clause , Join ):
614+ raise exc .CompileError (
615+ "Excel dialect does not support JOIN inside subqueries"
616+ )
617+ self ._reject_correlated_subquery (select_inner )
590618
591619 self ._subquery_depth += 1
592620 try :
@@ -598,7 +626,8 @@ def visit_subquery(self, subquery: Any, **kw: Any) -> str:
598626
599627 def visit_grouping (self , grouping : Any , asfrom : bool = False , ** kwargs : Any ) -> str :
600628 element = getattr (grouping , "element" , None )
601- is_subquery_select = getattr (element , "__visit_name__" , None ) == "select"
629+ visit_name = getattr (element , "__visit_name__" , None )
630+ is_subquery_select = visit_name in {"select" , "compound_select" }
602631 if is_subquery_select :
603632 if not self ._in_in_clause :
604633 raise exc .CompileError (
@@ -616,13 +645,18 @@ def visit_grouping(self, grouping: Any, asfrom: bool = False, **kwargs: Any) ->
616645 )
617646
618647 assert element is not None # guaranteed by is_subquery_select check
619- # Reject subqueries that themselves contain a JOIN
620- for from_clause in element .get_final_froms ():
621- if isinstance (from_clause , Join ):
622- raise exc .CompileError (
623- "Excel dialect does not support JOIN inside subqueries"
624- )
625- self ._reject_correlated_subquery (element )
648+ if visit_name == "compound_select" :
649+ self ._guard_subquery_shape (cast ("CompoundSelect[Any]" , element ))
650+ elif visit_name == "select" :
651+ select_element = cast ("Select[Any]" , element )
652+ self ._guard_subquery_shape (select_element )
653+ # Reject subqueries that themselves contain a JOIN
654+ for from_clause in select_element .get_final_froms ():
655+ if isinstance (from_clause , Join ):
656+ raise exc .CompileError (
657+ "Excel dialect does not support JOIN inside subqueries"
658+ )
659+ self ._reject_correlated_subquery (select_element )
626660 kwargs ["literal_binds" ] = True
627661
628662 if is_subquery_select :
0 commit comments