@@ -6,7 +6,7 @@ use thiserror::Error;
6
6
7
7
use petgraph:: algo:: toposort;
8
8
use petgraph:: prelude:: StableGraph ;
9
- use petgraph:: { Directed , Incoming , Outgoing } ;
9
+ use petgraph:: { Directed , Outgoing } ;
10
10
11
11
use partiql_value:: Value :: { Boolean , Missing , Null } ;
12
12
use partiql_value:: {
@@ -18,7 +18,7 @@ use crate::env::basic::MapBindings;
18
18
use crate :: env:: Bindings ;
19
19
20
20
#[ derive( Debug ) ]
21
- pub struct EvalPlan ( pub StableGraph < Box < dyn Evaluable > , ( ) , Directed > ) ;
21
+ pub struct EvalPlan ( pub StableGraph < Box < dyn Evaluable > , u8 , Directed > ) ;
22
22
23
23
impl Default for EvalPlan {
24
24
fn default ( ) -> Self {
@@ -28,7 +28,7 @@ impl Default for EvalPlan {
28
28
29
29
impl EvalPlan {
30
30
fn new ( ) -> Self {
31
- EvalPlan ( StableGraph :: < Box < dyn Evaluable > , ( ) , Directed > :: new ( ) )
31
+ EvalPlan ( StableGraph :: < Box < dyn Evaluable > , u8 , Directed > :: new ( ) )
32
32
}
33
33
}
34
34
@@ -50,7 +50,7 @@ pub enum EvaluationError {
50
50
51
51
pub trait Evaluable : Debug {
52
52
fn evaluate ( & mut self , ctx : & dyn EvalContext ) -> Option < Value > ;
53
- fn update_input ( & mut self , input : & Value ) ;
53
+ fn update_input ( & mut self , input : & Value , branch_num : u8 ) ;
54
54
}
55
55
56
56
#[ derive( Debug ) ]
@@ -108,11 +108,103 @@ impl Evaluable for EvalScan {
108
108
self . output . clone ( )
109
109
}
110
110
111
- fn update_input ( & mut self , _input : & Value ) {
111
+ fn update_input ( & mut self , _input : & Value , _branch_num : u8 ) {
112
112
todo ! ( "update_input for Scan" )
113
113
}
114
114
}
115
115
116
+ #[ derive( Debug ) ]
117
+ pub enum EvalJoinKind {
118
+ Inner ,
119
+ Left ,
120
+ Right ,
121
+ Full ,
122
+ Cross ,
123
+ }
124
+
125
+ #[ derive( Debug ) ]
126
+ pub struct EvalJoin {
127
+ pub kind : EvalJoinKind ,
128
+ pub on : Option < Box < dyn EvalExpr > > ,
129
+ pub input_l : Option < Value > ,
130
+ pub input_r : Option < Value > ,
131
+ pub output : Option < Value > ,
132
+ }
133
+
134
+ impl EvalJoin {
135
+ pub fn new ( kind : EvalJoinKind , on : Option < Box < dyn EvalExpr > > ) -> Self {
136
+ EvalJoin {
137
+ kind,
138
+ on,
139
+ input_l : None ,
140
+ input_r : None ,
141
+ output : None ,
142
+ }
143
+ }
144
+ }
145
+
146
+ impl Evaluable for EvalJoin {
147
+ fn evaluate ( & mut self , ctx : & dyn EvalContext ) -> Option < Value > {
148
+ // TODO: PartiQL defaults to lateral JOINs (RHS can reference binding tuples defined from the LHS)
149
+ // https://partiql.org/assets/PartiQL-Specification.pdf#subsection.5.3. Adding this behavior
150
+ // to be spec-compliant may result in changes to the DAG flows.
151
+ let output = match self . kind {
152
+ EvalJoinKind :: Inner => {
153
+ let mut result = partiql_bag ! ( ) ;
154
+ for binding_tuple_l in self . input_l . clone ( ) . unwrap ( ) {
155
+ let binding_tuple_l = binding_tuple_l. coerce_to_tuple ( ) ;
156
+ for binding_tuple_r in self . input_r . clone ( ) . unwrap ( ) {
157
+ let binding_tuple_r = binding_tuple_r. coerce_to_tuple ( ) ;
158
+ let mut new_result = binding_tuple_l. clone ( ) ;
159
+ for pairs in binding_tuple_r. pairs ( ) {
160
+ new_result. insert ( pairs. 0 , pairs. 1 . clone ( ) ) ;
161
+ }
162
+ if let Some ( on_condition) = & self . on {
163
+ if on_condition. evaluate ( & new_result, ctx) == Boolean ( true ) {
164
+ result. push ( new_result. into ( ) ) ;
165
+ }
166
+ } else {
167
+ result. push ( new_result. into ( ) ) ;
168
+ }
169
+ }
170
+ }
171
+ Some ( result. into ( ) )
172
+ }
173
+ EvalJoinKind :: Left => {
174
+ todo ! ( "Left JOINs" )
175
+ }
176
+ EvalJoinKind :: Cross => {
177
+ let mut result = partiql_bag ! ( ) ;
178
+ for binding_tuple_l in self . input_l . clone ( ) . unwrap ( ) {
179
+ let binding_tuple_l = binding_tuple_l. coerce_to_tuple ( ) ;
180
+ for binding_tuple_r in self . input_r . clone ( ) . unwrap ( ) {
181
+ let binding_tuple_r = binding_tuple_r. coerce_to_tuple ( ) ;
182
+ let mut new_result = binding_tuple_l. clone ( ) ;
183
+ for pairs in binding_tuple_r. pairs ( ) {
184
+ new_result. insert ( pairs. 0 , pairs. 1 . clone ( ) ) ;
185
+ }
186
+ result. push ( new_result. into ( ) ) ;
187
+ }
188
+ }
189
+ Some ( result. into ( ) )
190
+ }
191
+ EvalJoinKind :: Full | EvalJoinKind :: Right => {
192
+ todo ! ( "Full and Right Joins are not yet implemented for `partiql-lang-rust`" )
193
+ }
194
+ } ;
195
+ self . output = output;
196
+ self . output . clone ( )
197
+ }
198
+
199
+ fn update_input ( & mut self , input : & Value , branch_num : u8 ) {
200
+ match branch_num {
201
+ 0 => self . input_l = Some ( input. clone ( ) ) ,
202
+ 1 => self . input_r = Some ( input. clone ( ) ) ,
203
+ _ => panic ! ( "EvalJoin nodes only support `0` and `1` for the `branch_num`" ) ,
204
+ } ;
205
+ }
206
+ }
207
+
116
208
#[ derive( Debug ) ]
117
209
pub struct EvalUnpivot {
118
210
pub expr : Box < dyn EvalExpr > ,
@@ -154,7 +246,7 @@ impl Evaluable for EvalUnpivot {
154
246
self . output . clone ( )
155
247
}
156
248
157
- fn update_input ( & mut self , _input : & Value ) {
249
+ fn update_input ( & mut self , _input : & Value , _branch_num : u8 ) {
158
250
todo ! ( )
159
251
}
160
252
}
@@ -206,7 +298,7 @@ impl Evaluable for EvalFilter {
206
298
self . output = Some ( Value :: Bag ( Box :: new ( out) ) ) ;
207
299
self . output . clone ( )
208
300
}
209
- fn update_input ( & mut self , input : & Value ) {
301
+ fn update_input ( & mut self , input : & Value , _branch_num : u8 ) {
210
302
self . input = Some ( input. clone ( ) )
211
303
}
212
304
}
@@ -257,7 +349,7 @@ impl Evaluable for EvalProject {
257
349
self . output . clone ( )
258
350
}
259
351
260
- fn update_input ( & mut self , input : & Value ) {
352
+ fn update_input ( & mut self , input : & Value , _branch_num : u8 ) {
261
353
self . input = Some ( input. clone ( ) ) ;
262
354
}
263
355
}
@@ -304,7 +396,7 @@ impl Evaluable for EvalProjectValue {
304
396
self . output . clone ( )
305
397
}
306
398
307
- fn update_input ( & mut self , input : & Value ) {
399
+ fn update_input ( & mut self , input : & Value , _branch_num : u8 ) {
308
400
self . input = Some ( input. clone ( ) ) ;
309
401
}
310
402
}
@@ -436,7 +528,7 @@ impl Evaluable for EvalDistinct {
436
528
self . output . clone ( )
437
529
}
438
530
439
- fn update_input ( & mut self , input : & Value ) {
531
+ fn update_input ( & mut self , input : & Value , _branch_num : u8 ) {
440
532
self . input = Some ( input. clone ( ) ) ;
441
533
}
442
534
}
@@ -451,7 +543,7 @@ impl Evaluable for EvalSink {
451
543
fn evaluate ( & mut self , _ctx : & dyn EvalContext ) -> Option < Value > {
452
544
self . input . clone ( )
453
545
}
454
- fn update_input ( & mut self , input : & Value ) {
546
+ fn update_input ( & mut self , input : & Value , _branch_num : u8 ) {
455
547
self . input = Some ( input. clone ( ) ) ;
456
548
}
457
549
}
@@ -627,39 +719,33 @@ impl Evaluator {
627
719
// that all v ∈ V \{v0} are reachable from v0. Note that this is the definition of trees
628
720
// without the condition |E| = |V | − 1. Hence, all trees are DAGs.
629
721
// Reference: https://link.springer.com/article/10.1007/s00450-009-0061-0
630
- match graph. externals ( Incoming ) . exactly_one ( ) {
631
- Ok ( _) => {
632
- let sorted_ops = toposort ( & graph, None ) ;
633
- match sorted_ops {
634
- Ok ( ops) => {
635
- let mut result = None ;
636
- for idx in ops. into_iter ( ) {
637
- let src = graph
638
- . node_weight_mut ( idx)
639
- . expect ( "Error in retrieving node" ) ;
640
- result = src. evaluate ( & * self . ctx ) ;
641
-
642
- let mut ne = graph. neighbors_directed ( idx, Outgoing ) . detach ( ) ;
643
- while let Some ( n) = ne. next_node ( & graph) {
644
- let dst =
645
- graph. node_weight_mut ( n) . expect ( "Error in retrieving node" ) ;
646
- dst. update_input (
647
- & result. clone ( ) . expect ( "Error in retrieving source value" ) ,
648
- ) ;
649
- }
650
- }
651
- let evaluated = Evaluated {
652
- result : result. expect ( "Error in retrieving eval output" ) ,
653
- } ;
654
- Ok ( evaluated)
722
+ let sorted_ops = toposort ( & graph, None ) ;
723
+ match sorted_ops {
724
+ Ok ( ops) => {
725
+ let mut result = None ;
726
+ for idx in ops. into_iter ( ) {
727
+ let src = graph
728
+ . node_weight_mut ( idx)
729
+ . expect ( "Error in retrieving node" ) ;
730
+ result = src. evaluate ( & * self . ctx ) ;
731
+
732
+ let mut ne = graph. neighbors_directed ( idx, Outgoing ) . detach ( ) ;
733
+ while let Some ( ( e, n) ) = ne. next ( & graph) {
734
+ // use the edge weight to store the `branch_num`
735
+ let branch_num = * graph
736
+ . edge_weight ( e)
737
+ . expect ( "Error in retrieving weight for edge" ) ;
738
+ let dst = graph. node_weight_mut ( n) . expect ( "Error in retrieving node" ) ;
739
+ dst. update_input (
740
+ & result. clone ( ) . expect ( "Error in retrieving source value" ) ,
741
+ branch_num,
742
+ ) ;
655
743
}
656
- Err ( e) => Err ( EvalErr {
657
- errors : vec ! [ EvaluationError :: InvalidEvaluationPlan ( format!(
658
- "Malformed evaluation plan detected: {:?}" ,
659
- e
660
- ) ) ] ,
661
- } ) ,
662
744
}
745
+ let evaluated = Evaluated {
746
+ result : result. expect ( "Error in retrieving eval output" ) ,
747
+ } ;
748
+ Ok ( evaluated)
663
749
}
664
750
Err ( e) => Err ( EvalErr {
665
751
errors : vec ! [ EvaluationError :: InvalidEvaluationPlan ( format!(
0 commit comments