@@ -421,24 +421,33 @@ def visit_list_expression(self, node, unmangle_names):
421421 else :
422422 return "(%s)" % self ._join_expressions (node .values , unmangle_names )
423423
424+ def visit_window_func (self , node , unmangle_names ):
425+ args = ", " .join ([self .process (arg , unmangle_names ) for arg in node .func_args ])
426+ ignore_null = f" { node .ignore_null } NULLS" if node .ignore_null else ""
427+ window_spec = " OVER " + self .process (node .window_spec , unmangle_names )
428+ return f"{ node .func_name .upper ()} ({ args } ){ ignore_null } { window_spec } "
429+
424430 def visit_window_spec (self , node , unmangle_names ):
425- parts = []
431+ if node .window_name is not None :
432+ return node .window_name
426433
434+ parts = []
427435 if node .partition_by :
428- parts .append (
429- "PARTITION BY "
430- + self ._join_expressions (node .partition_by , unmangle_names )
431- )
436+ self .process (node .partition_by , unmangle_names )
432437 if node .order_by :
433438 parts .append ("ORDER BY " + format_sort_items (node .order_by , unmangle_names ))
434- if node .frame :
435- parts .append (self .process (node .frame , unmangle_names ))
436-
439+ if node .frame_clause :
440+ parts .append (self .process (node .frame_clause , unmangle_names ))
437441 return '(' + ' ' .join (parts ) + ')'
438442
439- def visit_window_frame (self , node , unmangle_names ):
440- ret = node .type + " "
443+ def visit_partition_by_clause (self , node , unmangle_names ):
444+ return "PARTITION BY " + self ._join_expressions (node .items , unmangle_names )
445+
446+ def visit_frame_clause (self , node , unmangle_names ):
447+ return f"{ node .type } { self .process (node .frame_range , unmangle_names )} "
441448
449+ def visit_window_frame (self , node , unmangle_names ):
450+ ret = ""
442451 if node .end :
443452 ret += "BETWEEN %s AND %s" % (
444453 self .process (node .start , unmangle_names ),
@@ -449,6 +458,19 @@ def visit_window_frame(self, node, unmangle_names):
449458
450459 return ret
451460
461+ def visit_frame_bound (self , node , unmangle_names ):
462+ if node .type .upper () == "ROW" :
463+ return "CURRENT ROW"
464+ expr = (
465+ self .process (node .expr , unmangle_names )
466+ if node .expr is not None
467+ else "UNBOUNDED "
468+ )
469+ return f"{ expr } { node .type .upper ()} "
470+
471+ def visit_frame_expr (self , node , unmangle_names ):
472+ return self .process (node .value , unmangle_names )
473+
452474 def visit_single_column (self , node , indent ):
453475 format_expression (node .expression )
454476
@@ -468,6 +490,9 @@ def visit_match_against_expression(self, node, unmangle_names):
468490 full_text_search_modifier = full_text_search_modifier .upper ()
469491 return f"MATCH({ columns } ) AGAINST ({ self .process (node .expr , unmangle_names )} { full_text_search_modifier } )"
470492
493+ def visit_sound_like (self , node , unmangle_names ):
494+ return f"{ self .process (node .arguments [0 ])} SOUNDS LIKE { self .process (node .arguments [1 ])} "
495+
471496 def _format_binary_expression (self , operator , left , right , unmangle_names ):
472497 return "%s %s %s" % (
473498 self .process (left , unmangle_names ),
@@ -689,13 +714,14 @@ def visit_table_subquery(self, node, indent):
689714 return None
690715
691716 def visit_union (self , node , indent ):
692- all = node .all
693717 for i , relation in enumerate (node .relations ):
694718 self ._process_relation (relation , indent )
695719 self .builder .append ("\n " )
696720 if i != len (node .relations ) - 1 :
697- if all :
721+ if node . all :
698722 self ._append (indent , "UNION ALL" )
723+ elif node .distinct :
724+ self ._append (indent , "UNION DISTINCT" )
699725 else :
700726 self ._append (indent , "UNION" )
701727 self .builder .append ("\n " )
@@ -704,7 +730,12 @@ def visit_union(self, node, indent):
704730
705731 def visit_except (self , node , indent ):
706732 self ._process_relation (node .left , indent )
707- self .builder .append ("EXCEPT " + "ALL " if not node .distinct else "" )
733+ if node .all is not None :
734+ self ._append (indent , "EXCEPT ALL" )
735+ elif node .distinct is not None :
736+ self ._append (indent , "EXCEPT DISTINCT" )
737+ else :
738+ self ._append (indent , "EXCEPT" )
708739 self ._process_relation (node .right , indent )
709740
710741 return None
@@ -756,7 +787,11 @@ def visit_intersect(self, node, indent):
756787 relations = [
757788 self ._process_relation (relation , indent ) for relation in node .relations
758789 ]
759- intersect = "INTERSECT " + "ALL " if not node .distinct else ""
790+ intersect = "INTERSECT"
791+ if node .all is not None :
792+ intersect += " ALL"
793+ elif node .distinct is not None :
794+ intersect += " DISTINCT"
760795 self .builder .append (intersect .join (relations ))
761796 return None
762797
0 commit comments