@@ -7,16 +7,17 @@ use partiql_ast::ast::{
77 Assignment , Bag , Between , BinOp , BinOpKind , Call , CallAgg , CallArg , CallArgNamed ,
88 CaseSensitivity , CreateIndex , CreateTable , Ddl , DdlOp , Delete , Dml , DmlOp , DropIndex ,
99 DropTable , FromClause , FromLet , FromLetKind , GroupByExpr , GroupKey , GroupingStrategy , Insert ,
10- InsertValue , Item , Join , JoinKind , JoinSpec , Like , List , Lit , NodeId , OnConflict , OrderByExpr ,
11- Path , PathStep , ProjectExpr , Projection , ProjectionKind , Query , QuerySet , Remove , SearchedCase ,
12- Select , Set , SetExpr , SetQuantifier , Sexp , SimpleCase , Struct , SymbolPrimitive , UniOp ,
13- UniOpKind , VarRef ,
10+ InsertValue , Item , Join , JoinKind , JoinSpec , Like , List , Lit , NodeId , NullOrderingSpec ,
11+ OnConflict , OrderByExpr , OrderingSpec , Path , PathStep , ProjectExpr , Projection , ProjectionKind ,
12+ Query , QuerySet , Remove , SearchedCase , Select , Set , SetExpr , SetQuantifier , Sexp , SimpleCase ,
13+ SortSpec , Struct , SymbolPrimitive , UniOp , UniOpKind , VarRef ,
1414} ;
1515use partiql_ast:: visit:: { Visit , Visitor } ;
1616use partiql_logical as logical;
1717use partiql_logical:: {
1818 BagExpr , BetweenExpr , BindingsOp , IsTypeExpr , LikeMatch , LikeNonStringNonLiteralMatch ,
19- ListExpr , LogicalPlan , OpId , PathComponent , Pattern , PatternMatchExpr , TupleExpr , ValueExpr ,
19+ ListExpr , LogicalPlan , OpId , PathComponent , Pattern , PatternMatchExpr , SortSpecOrder ,
20+ TupleExpr , ValueExpr ,
2021} ;
2122
2223use partiql_value:: { BindingsName , Value } ;
@@ -26,6 +27,7 @@ use std::collections::{HashMap, HashSet};
2627use crate :: call_defs:: { CallArgument , FnSymTab , FN_SYM_TAB } ;
2728use crate :: name_resolver;
2829use itertools:: Itertools ;
30+
2931use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
3032
3133type FnvIndexMap < K , V > = IndexMap < K , V , FnvBuildHasher > ;
@@ -34,6 +36,7 @@ type FnvIndexMap<K, V> = IndexMap<K, V, FnvBuildHasher>;
3436enum QueryContext {
3537 FromLet ,
3638 Path ,
39+ Order ,
3740 Query ,
3841}
3942
@@ -104,6 +107,7 @@ pub struct AstToLogical {
104107 vexpr_stack : Vec < Vec < ValueExpr > > ,
105108 arg_stack : Vec < Vec < CallArgument > > ,
106109 path_stack : Vec < Vec < PathComponent > > ,
110+ sort_stack : Vec < Vec < logical:: SortSpec > > ,
107111
108112 from_lets : HashSet < ast:: NodeId > ,
109113
@@ -166,6 +170,7 @@ impl AstToLogical {
166170 vexpr_stack : Default :: default ( ) ,
167171 arg_stack : Default :: default ( ) ,
168172 path_stack : Default :: default ( ) ,
173+ sort_stack : Default :: default ( ) ,
169174
170175 from_lets : Default :: default ( ) ,
171176
@@ -406,6 +411,23 @@ impl AstToLogical {
406411 fn push_path_step ( & mut self , step : PathComponent ) {
407412 self . path_stack . last_mut ( ) . unwrap ( ) . push ( step) ;
408413 }
414+
415+ #[ inline]
416+ fn enter_sort ( & mut self ) {
417+ self . sort_stack . push ( vec ! [ ] ) ;
418+ self . ctx_stack . push ( QueryContext :: Order ) ;
419+ }
420+
421+ #[ inline]
422+ fn exit_sort ( & mut self ) -> Vec < logical:: SortSpec > {
423+ self . ctx_stack . pop ( ) ;
424+ self . sort_stack . pop ( ) . expect ( "sort specs" )
425+ }
426+
427+ #[ inline]
428+ fn push_sort_spec ( & mut self , spec : logical:: SortSpec ) {
429+ self . sort_stack . last_mut ( ) . unwrap ( ) . push ( spec) ;
430+ }
409431}
410432
411433// SQL (and therefore PartiQL) text (and therefore AST) is not lexically-scoped as is the
@@ -1158,12 +1180,48 @@ impl<'ast> Visitor<'ast> for AstToLogical {
11581180 }
11591181
11601182 fn enter_order_by_expr ( & mut self , _order_by_expr : & ' ast OrderByExpr ) {
1161- self . enter_env ( ) ;
1183+ self . enter_sort ( ) ;
11621184 }
11631185
11641186 fn exit_order_by_expr ( & mut self , _order_by_expr : & ' ast OrderByExpr ) {
1165- let _env = self . exit_env ( ) ;
1166- todo ! ( "order by clause" ) ;
1187+ let specs = self . exit_sort ( ) ;
1188+ let order_by = logical:: BindingsOp :: OrderBy ( logical:: OrderBy { specs } ) ;
1189+ let id = self . plan . add_operator ( order_by) ;
1190+ self . current_clauses_mut ( ) . order_by_clause . replace ( id) ;
1191+ }
1192+
1193+ fn enter_sort_spec ( & mut self , _sort_spec : & ' ast SortSpec ) {
1194+ self . enter_env ( ) ;
1195+ }
1196+
1197+ fn exit_sort_spec ( & mut self , sort_spec : & ' ast SortSpec ) {
1198+ let mut env = self . exit_env ( ) ;
1199+ assert_eq ! ( env. len( ) , 1 ) ;
1200+
1201+ let expr = env. pop ( ) . unwrap ( ) ;
1202+ let order = match sort_spec
1203+ . ordering_spec
1204+ . as_ref ( )
1205+ . unwrap_or ( & OrderingSpec :: Asc )
1206+ {
1207+ OrderingSpec :: Asc => logical:: SortSpecOrder :: Asc ,
1208+ OrderingSpec :: Desc => logical:: SortSpecOrder :: Desc ,
1209+ } ;
1210+
1211+ let null_order = match sort_spec. null_ordering_spec {
1212+ None => match order {
1213+ SortSpecOrder :: Asc => logical:: SortSpecNullOrder :: Last ,
1214+ SortSpecOrder :: Desc => logical:: SortSpecNullOrder :: First ,
1215+ } ,
1216+ Some ( NullOrderingSpec :: First ) => logical:: SortSpecNullOrder :: First ,
1217+ Some ( NullOrderingSpec :: Last ) => logical:: SortSpecNullOrder :: Last ,
1218+ } ;
1219+
1220+ self . push_sort_spec ( logical:: SortSpec {
1221+ expr,
1222+ order,
1223+ null_order,
1224+ } ) ;
11671225 }
11681226
11691227 fn enter_limit_offset_clause ( & mut self , _limit_offset : & ' ast ast:: LimitOffsetClause ) {
0 commit comments