44//! serializes filters to msgpack, and handles broadcast join decisions.
55
66use nodedb_sql:: types:: {
7- AggregateExpr , EngineType , Filter , FilterExpr , JoinType , Projection , SortKey , SqlExpr , SqlPlan ,
8- SqlValue ,
7+ AggregateExpr , EngineType , Filter , FilterExpr , Projection , SortKey , SqlExpr , SqlPlan , SqlValue ,
98} ;
109
1110use std:: sync:: Arc ;
@@ -57,6 +56,7 @@ fn convert_one(
5756 tenant_id,
5857 vshard_id: VShardId :: from_collection( "" ) ,
5958 plan: PhysicalPlan :: Meta ( MetaOp :: RawResponse { payload } ) ,
59+ post_dedup: false ,
6060 } ] )
6161 }
6262
@@ -121,6 +121,7 @@ fn convert_one(
121121 tenant_id,
122122 vshard_id: vshard,
123123 plan: physical,
124+ post_dedup: false ,
124125 } ] )
125126 }
126127
@@ -147,6 +148,7 @@ fn convert_one(
147148 tenant_id,
148149 vshard_id: vshard,
149150 plan: physical,
151+ post_dedup: false ,
150152 } ] )
151153 }
152154
@@ -188,6 +190,7 @@ fn convert_one(
188190 plan: PhysicalPlan :: Document ( DocumentOp :: Truncate {
189191 collection: collection. clone( ) ,
190192 } ) ,
193+ post_dedup: false ,
191194 } ] )
192195 }
193196
@@ -197,8 +200,33 @@ fn convert_one(
197200 on,
198201 join_type,
199202 limit,
203+ projection,
204+ filters,
200205 ..
201- } => convert_join ( left, right, on, join_type, * limit, tenant_id) ,
206+ } => {
207+ let left_collection = extract_collection_name ( left) ;
208+ let right_collection = extract_collection_name ( right) ;
209+ let vshard = VShardId :: from_collection ( & left_collection) ;
210+ let proj_names = extract_projection_names ( projection) ;
211+ let filter_bytes = serialize_filters ( filters) ?;
212+
213+ Ok ( vec ! [ PhysicalTask {
214+ tenant_id,
215+ vshard_id: vshard,
216+ plan: PhysicalPlan :: Query ( QueryOp :: HashJoin {
217+ left_collection,
218+ right_collection,
219+ on: on. to_vec( ) ,
220+ join_type: join_type. as_str( ) . to_string( ) ,
221+ limit: * limit,
222+ post_group_by: Vec :: new( ) ,
223+ post_aggregates: Vec :: new( ) ,
224+ projection: proj_names,
225+ post_filters: filter_bytes,
226+ } ) ,
227+ post_dedup: false ,
228+ } ] )
229+ }
202230
203231 SqlPlan :: Aggregate {
204232 input,
@@ -260,6 +288,7 @@ fn convert_one(
260288 gap_fill: gap_fill. clone( ) ,
261289 rls_filters: Vec :: new( ) ,
262290 } ) ,
291+ post_dedup: false ,
263292 } ] )
264293 }
265294
@@ -275,6 +304,7 @@ fn convert_one(
275304 format: "json" . into( ) ,
276305 wal_lsn: None ,
277306 } ) ,
307+ post_dedup: false ,
278308 } ] )
279309 }
280310
@@ -300,6 +330,7 @@ fn convert_one(
300330 field_name: field. clone( ) ,
301331 rls_filters: filter_bytes,
302332 } ) ,
333+ post_dedup: false ,
303334 } ] )
304335 }
305336
@@ -321,6 +352,7 @@ fn convert_one(
321352 fuzzy: * fuzzy,
322353 rls_filters: Vec :: new( ) ,
323354 } ) ,
355+ post_dedup: false ,
324356 } ] )
325357 }
326358
@@ -348,6 +380,7 @@ fn convert_one(
348380 filter_bitmap: None ,
349381 rls_filters: Vec :: new( ) ,
350382 } ) ,
383+ post_dedup: false ,
351384 } ] )
352385 }
353386
@@ -384,6 +417,7 @@ fn convert_one(
384417 projection: proj_names,
385418 rls_filters: Vec :: new( ) ,
386419 } ) ,
420+ post_dedup: false ,
387421 } ] )
388422 }
389423
@@ -392,8 +426,11 @@ fn convert_one(
392426 for input in inputs {
393427 all_tasks. extend ( convert_one ( input, tenant_id, ctx) ?) ;
394428 }
395- // TODO: if distinct == true, wrap in a dedup stage.
396- let _ = distinct;
429+ if * distinct {
430+ for task in & mut all_tasks {
431+ task. post_dedup = true ;
432+ }
433+ }
397434 Ok ( all_tasks)
398435 }
399436
@@ -417,6 +454,7 @@ fn convert_one(
417454 distinct: * distinct,
418455 limit: * limit,
419456 } ) ,
457+ post_dedup: false ,
420458 } ] )
421459 }
422460
@@ -462,6 +500,7 @@ fn convert_insert(
462500 value : value_bytes,
463501 ttl_ms : 0 ,
464502 } ) ,
503+ post_dedup : false ,
465504 } ) ;
466505 }
467506 _ => {
@@ -473,6 +512,7 @@ fn convert_insert(
473512 document_id : doc_id,
474513 value : value_bytes,
475514 } ) ,
515+ post_dedup : false ,
476516 } ) ;
477517 }
478518 }
@@ -515,6 +555,7 @@ fn convert_update(
515555 key : sql_value_to_bytes ( key) ,
516556 updates : field_updates,
517557 } ) ,
558+ post_dedup : false ,
518559 } ) ;
519560 }
520561 return Ok ( tasks) ;
@@ -533,6 +574,7 @@ fn convert_update(
533574 updates : updates. clone ( ) ,
534575 returning,
535576 } ) ,
577+ post_dedup : false ,
536578 } ) ;
537579 }
538580 Ok ( tasks)
@@ -546,6 +588,7 @@ fn convert_update(
546588 updates,
547589 returning,
548590 } ) ,
591+ post_dedup: false ,
549592 } ] )
550593 }
551594}
@@ -569,6 +612,7 @@ fn convert_delete(
569612 collection: collection. into( ) ,
570613 keys,
571614 } ) ,
615+ post_dedup: false ,
572616 } ] ) ;
573617 }
574618
@@ -582,6 +626,7 @@ fn convert_delete(
582626 collection : collection. into ( ) ,
583627 document_id : sql_value_to_string ( key) ,
584628 } ) ,
629+ post_dedup : false ,
585630 } ) ;
586631 }
587632 Ok ( tasks)
@@ -594,39 +639,11 @@ fn convert_delete(
594639 collection: collection. into( ) ,
595640 filters: filter_bytes,
596641 } ) ,
642+ post_dedup: false ,
597643 } ] )
598644 }
599645}
600646
601- fn convert_join (
602- left : & SqlPlan ,
603- right : & SqlPlan ,
604- on : & [ ( String , String ) ] ,
605- join_type : & JoinType ,
606- limit : usize ,
607- tenant_id : TenantId ,
608- ) -> crate :: Result < Vec < PhysicalTask > > {
609- let left_collection = extract_collection_name ( left) ;
610- let right_collection = extract_collection_name ( right) ;
611- let vshard = VShardId :: from_collection ( & left_collection) ;
612-
613- let on_pairs: Vec < ( String , String ) > = on. to_vec ( ) ;
614-
615- Ok ( vec ! [ PhysicalTask {
616- tenant_id,
617- vshard_id: vshard,
618- plan: PhysicalPlan :: Query ( QueryOp :: HashJoin {
619- left_collection,
620- right_collection,
621- on: on_pairs,
622- join_type: join_type. as_str( ) . to_string( ) ,
623- limit,
624- post_group_by: Vec :: new( ) ,
625- post_aggregates: Vec :: new( ) ,
626- } ) ,
627- } ] )
628- }
629-
630647fn convert_aggregate (
631648 input : & SqlPlan ,
632649 group_by : & [ SqlExpr ] ,
@@ -666,7 +683,10 @@ fn convert_aggregate(
666683 limit: * join_limit,
667684 post_group_by: group_strs,
668685 post_aggregates: agg_pairs,
686+ projection: Vec :: new( ) ,
687+ post_filters: Vec :: new( ) ,
669688 } ) ,
689+ post_dedup: false ,
670690 } ] ) ;
671691 }
672692
@@ -698,6 +718,7 @@ fn convert_aggregate(
698718 sub_group_by: Vec :: new( ) ,
699719 sub_aggregates: Vec :: new( ) ,
700720 } ) ,
721+ post_dedup: false ,
701722 } ] )
702723}
703724
@@ -749,9 +770,50 @@ fn extract_computed_columns(proj: &[Projection]) -> crate::Result<Vec<u8>> {
749770 } )
750771}
751772
752- fn serialize_window_functions ( _specs : & [ nodedb_sql:: types:: WindowSpec ] ) -> crate :: Result < Vec < u8 > > {
753- // TODO: serialize window function specs.
754- Ok ( Vec :: new ( ) )
773+ fn serialize_window_functions ( specs : & [ nodedb_sql:: types:: WindowSpec ] ) -> crate :: Result < Vec < u8 > > {
774+ if specs. is_empty ( ) {
775+ return Ok ( Vec :: new ( ) ) ;
776+ }
777+ let bridge_specs: Vec < crate :: bridge:: window_func:: WindowFuncSpec > = specs
778+ . iter ( )
779+ . map ( |s| crate :: bridge:: window_func:: WindowFuncSpec {
780+ alias : s. alias . clone ( ) ,
781+ func_name : s. function . clone ( ) ,
782+ args : s. args . iter ( ) . map ( sql_expr_to_bridge_expr) . collect ( ) ,
783+ partition_by : s
784+ . partition_by
785+ . iter ( )
786+ . filter_map ( |e| match e {
787+ SqlExpr :: Column { name, .. } => Some ( name. clone ( ) ) ,
788+ _ => None ,
789+ } )
790+ . collect ( ) ,
791+ order_by : s
792+ . order_by
793+ . iter ( )
794+ . filter_map ( |k| match & k. expr {
795+ SqlExpr :: Column { name, .. } => Some ( ( name. clone ( ) , k. ascending ) ) ,
796+ _ => None ,
797+ } )
798+ . collect ( ) ,
799+ frame : crate :: bridge:: window_func:: WindowFrame :: default ( ) ,
800+ } )
801+ . collect ( ) ;
802+ zerompk:: to_msgpack_vec ( & bridge_specs) . map_err ( |e| crate :: Error :: Internal {
803+ detail : format ! ( "serialize window functions: {e}" ) ,
804+ } )
805+ }
806+
807+ /// Convert a `nodedb_sql::types::SqlExpr` (parser AST) to a
808+ /// `nodedb_query::expr::SqlExpr` (bridge evaluation type).
809+ fn sql_expr_to_bridge_expr ( expr : & SqlExpr ) -> crate :: bridge:: expr_eval:: SqlExpr {
810+ use crate :: bridge:: expr_eval:: SqlExpr as BExpr ;
811+ match expr {
812+ SqlExpr :: Column { name, .. } => BExpr :: Column ( name. clone ( ) ) ,
813+ SqlExpr :: Literal ( v) => BExpr :: Literal ( sql_value_to_json ( v) ) ,
814+ SqlExpr :: Wildcard => BExpr :: Column ( "*" . into ( ) ) ,
815+ _ => BExpr :: Literal ( serde_json:: Value :: Null ) ,
816+ }
755817}
756818
757819fn convert_sort_keys ( keys : & [ SortKey ] ) -> Vec < ( String , bool ) > {
0 commit comments