@ -86,6 +86,7 @@ pub enum PlanNode {
Project {
Project {
child : Box < Self > ,
child : Box < Self > ,
mapping : Rc < Vec < ( usize , usize ) > > , // pairs of (variable key in child, variable key in output)
mapping : Rc < Vec < ( usize , usize ) > > , // pairs of (variable key in child, variable key in output)
lateral_mapping : Rc < Vec < ( usize , usize ) > > , // pairs of (variable key in child, variable key in output)
} ,
} ,
Aggregate {
Aggregate {
// By definition the group by key are the range 0..key_mapping.len()
// By definition the group by key are the range 0..key_mapping.len()
@ -99,19 +100,17 @@ impl PlanNode {
/// Returns variables that might be bound in the result set
/// Returns variables that might be bound in the result set
pub fn used_variables ( & self ) -> BTreeSet < usize > {
pub fn used_variables ( & self ) -> BTreeSet < usize > {
let mut set = BTreeSet ::default ( ) ;
let mut set = BTreeSet ::default ( ) ;
self . lookup_used_variables ( & mut | v | {
self . add_used_variables ( & mut set ) ;
set . insert ( v ) ;
} ) ;
set
set
}
}
pub fn lookup _used_variables( & self , callback : & mut impl FnMut ( usize ) ) {
pub fn add _used_variables( & self , set : & mut BTreeSet < usize > ) {
match self {
match self {
Self ::StaticBindings { tuples } = > {
Self ::StaticBindings { tuples } = > {
for tuple in tuples {
for tuple in tuples {
for ( key , value ) in tuple . iter ( ) . enumerate ( ) {
for ( key , value ) in tuple . iter ( ) . enumerate ( ) {
if value . is_some ( ) {
if value . is_some ( ) {
callback ( key ) ;
set . insert ( key ) ;
}
}
}
}
}
}
@ -123,16 +122,16 @@ impl PlanNode {
graph_name ,
graph_name ,
} = > {
} = > {
if let PatternValue ::Variable ( var ) = subject {
if let PatternValue ::Variable ( var ) = subject {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = predicate {
if let PatternValue ::Variable ( var ) = predicate {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = object {
if let PatternValue ::Variable ( var ) = object {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = graph_name {
if let PatternValue ::Variable ( var ) = graph_name {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
}
}
Self ::PathPattern {
Self ::PathPattern {
@ -142,60 +141,69 @@ impl PlanNode {
..
..
} = > {
} = > {
if let PatternValue ::Variable ( var ) = subject {
if let PatternValue ::Variable ( var ) = subject {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = object {
if let PatternValue ::Variable ( var ) = object {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = graph_name {
if let PatternValue ::Variable ( var ) = graph_name {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
}
}
Self ::Filter { child , expression } = > {
Self ::Filter { child , expression } = > {
expression . lookup_used_variables ( callback ) ;
expression . add_used_variables ( set ) ;
child . lookup_used_variables ( callback ) ;
child . add_used_variables ( set ) ;
}
}
Self ::Union { children } = > {
Self ::Union { children } = > {
for child in children . iter ( ) {
for child in children . iter ( ) {
child . lookup_used_variables ( callback ) ;
child . add_used_variables ( set ) ;
}
}
}
}
Self ::HashJoin { left , right }
Self ::HashJoin { left , right }
| Self ::ForLoopJoin { left , right , .. }
| Self ::ForLoopJoin { left , right , .. }
| Self ::AntiJoin { left , right }
| Self ::AntiJoin { left , right }
| Self ::LeftJoin { left , right , .. } = > {
| Self ::LeftJoin { left , right , .. } = > {
left . lookup_used_variables ( callback ) ;
left . add_used_variables ( set ) ;
right . lookup_used_variables ( callback ) ;
right . add_used_variables ( set ) ;
}
}
Self ::Extend {
Self ::Extend {
child ,
child ,
position ,
position ,
expression ,
expression ,
} = > {
} = > {
callback ( * position ) ;
set . insert ( * position ) ;
expression . lookup_used_variables ( callback ) ;
expression . add_used_variables ( set ) ;
child . lookup_used_variables ( callback ) ;
child . add_used_variables ( set ) ;
}
}
Self ::Sort { child , .. }
Self ::Sort { child , .. }
| Self ::HashDeduplicate { child }
| Self ::HashDeduplicate { child }
| Self ::Reduced { child }
| Self ::Reduced { child }
| Self ::Skip { child , .. }
| Self ::Skip { child , .. }
| Self ::Limit { child , .. } = > child . lookup_used_variables ( callback ) ,
| Self ::Limit { child , .. } = > child . add_used_variables ( set ) ,
Self ::Service {
Self ::Service {
child ,
child ,
service_name ,
service_name ,
..
..
} = > {
} = > {
if let PatternValue ::Variable ( v ) = service_name {
if let PatternValue ::Variable ( v ) = service_name {
callback ( * v ) ;
set . insert ( * v ) ;
}
child . add_used_variables ( set ) ;
}
Self ::Project {
mapping ,
child ,
lateral_mapping ,
} = > {
let mut child_bound = child . used_variables ( ) ;
for ( child_i , output_i ) in lateral_mapping . iter ( ) {
if set . contains ( output_i ) {
child_bound . insert ( * child_i ) ;
}
}
child . lookup_used_variables ( callback ) ;
}
}
Self ::Project { mapping , child } = > {
let child_bound = child . used_variables ( ) ;
for ( child_i , output_i ) in mapping . iter ( ) {
for ( child_i , output_i ) in mapping . iter ( ) {
if child_bound . contains ( child_i ) {
if child_bound . contains ( child_i ) {
callback ( * output_i ) ;
set . insert ( * output_i ) ;
}
}
}
}
}
}
@ -205,10 +213,10 @@ impl PlanNode {
..
..
} = > {
} = > {
for var in key_variables . iter ( ) {
for var in key_variables . iter ( ) {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
for ( _ , var ) in aggregates . iter ( ) {
for ( _ , var ) in aggregates . iter ( ) {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
}
}
}
}
@ -219,13 +227,11 @@ impl PlanNode {
/// (subset because this function is not perfect yet)
/// (subset because this function is not perfect yet)
pub fn always_bound_variables ( & self ) -> BTreeSet < usize > {
pub fn always_bound_variables ( & self ) -> BTreeSet < usize > {
let mut set = BTreeSet ::default ( ) ;
let mut set = BTreeSet ::default ( ) ;
self . lookup_always_bound_variables ( & mut | v | {
self . add_always_bound_variables ( & mut set ) ;
set . insert ( v ) ;
} ) ;
set
set
}
}
pub fn lookup _always_bound_variables( & self , callback : & mut impl FnMut ( usize ) ) {
pub fn add _always_bound_variables( & self , set : & mut BTreeSet < usize > ) {
match self {
match self {
Self ::StaticBindings { tuples } = > {
Self ::StaticBindings { tuples } = > {
let mut variables = BTreeMap ::default ( ) ; // value true iff always bound
let mut variables = BTreeMap ::default ( ) ; // value true iff always bound
@ -246,7 +252,7 @@ impl PlanNode {
}
}
for ( k , v ) in variables {
for ( k , v ) in variables {
if v {
if v {
callback ( k ) ;
set . insert ( k ) ;
}
}
}
}
}
}
@ -257,16 +263,16 @@ impl PlanNode {
graph_name ,
graph_name ,
} = > {
} = > {
if let PatternValue ::Variable ( var ) = subject {
if let PatternValue ::Variable ( var ) = subject {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = predicate {
if let PatternValue ::Variable ( var ) = predicate {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = object {
if let PatternValue ::Variable ( var ) = object {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = graph_name {
if let PatternValue ::Variable ( var ) = graph_name {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
}
}
Self ::PathPattern {
Self ::PathPattern {
@ -276,18 +282,18 @@ impl PlanNode {
..
..
} = > {
} = > {
if let PatternValue ::Variable ( var ) = subject {
if let PatternValue ::Variable ( var ) = subject {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = object {
if let PatternValue ::Variable ( var ) = object {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
if let PatternValue ::Variable ( var ) = graph_name {
if let PatternValue ::Variable ( var ) = graph_name {
callback ( * var ) ;
set . insert ( * var ) ;
}
}
}
}
Self ::Filter { child , .. } = > {
Self ::Filter { child , .. } = > {
//TODO: have a look at the expression to know if it filters out unbound variables
//TODO: have a look at the expression to know if it filters out unbound variables
child . lookup_always_bound_variables ( callback ) ;
child . add_always_bound_variables ( set ) ;
}
}
Self ::Union { children } = > {
Self ::Union { children } = > {
if let Some ( vars ) = children
if let Some ( vars ) = children
@ -296,16 +302,16 @@ impl PlanNode {
. reduce ( | a , b | a . intersection ( & b ) . copied ( ) . collect ( ) )
. reduce ( | a , b | a . intersection ( & b ) . copied ( ) . collect ( ) )
{
{
for v in vars {
for v in vars {
callback ( v ) ;
set . insert ( v ) ;
}
}
}
}
}
}
Self ::HashJoin { left , right } | Self ::ForLoopJoin { left , right , .. } = > {
Self ::HashJoin { left , right } | Self ::ForLoopJoin { left , right , .. } = > {
left . lookup_always_bound_variables ( callback ) ;
left . add_always_bound_variables ( set ) ;
right . lookup_always_bound_variables ( callback ) ;
right . add_always_bound_variables ( set ) ;
}
}
Self ::AntiJoin { left , .. } | Self ::LeftJoin { left , .. } = > {
Self ::AntiJoin { left , .. } | Self ::LeftJoin { left , .. } = > {
left . lookup_always_bound_variables ( callback ) ;
left . add_always_bound_variables ( set ) ;
}
}
Self ::Extend {
Self ::Extend {
child ,
child ,
@ -314,27 +320,37 @@ impl PlanNode {
} = > {
} = > {
if matches! ( expression . as_ref ( ) , PlanExpression ::Constant ( _ ) ) {
if matches! ( expression . as_ref ( ) , PlanExpression ::Constant ( _ ) ) {
// TODO: more cases?
// TODO: more cases?
callback ( * position ) ;
set . insert ( * position ) ;
}
}
child . lookup_always_bound_variables ( callback ) ;
child . add_always_bound_variables ( set ) ;
}
}
Self ::Sort { child , .. }
Self ::Sort { child , .. }
| Self ::HashDeduplicate { child }
| Self ::HashDeduplicate { child }
| Self ::Reduced { child }
| Self ::Reduced { child }
| Self ::Skip { child , .. }
| Self ::Skip { child , .. }
| Self ::Limit { child , .. } = > child . lookup_always_bound_variables ( callback ) ,
| Self ::Limit { child , .. } = > child . add_always_bound_variables ( set ) ,
Self ::Service { child , silent , .. } = > {
Self ::Service { child , silent , .. } = > {
if * silent {
if * silent {
// none, might return a null tuple
// none, might return a null tuple
} else {
} else {
child . lookup_always_bound_variables ( callback )
child . add_always_bound_variables ( set )
}
}
}
}
Self ::Project { mapping , child } = > {
Self ::Project {
let child_bound = child . always_bound_variables ( ) ;
mapping ,
child ,
lateral_mapping ,
} = > {
let mut child_bound = BTreeSet ::new ( ) ;
for ( child_i , output_i ) in lateral_mapping . iter ( ) {
if set . contains ( output_i ) {
child_bound . insert ( * child_i ) ;
}
}
child . add_always_bound_variables ( & mut child_bound ) ;
for ( child_i , output_i ) in mapping . iter ( ) {
for ( child_i , output_i ) in mapping . iter ( ) {
if child_bound . contains ( child_i ) {
if child_bound . contains ( child_i ) {
callback ( * output_i ) ;
set . insert ( * output_i ) ;
}
}
}
}
}
}
@ -344,14 +360,12 @@ impl PlanNode {
}
}
}
}
pub fn is_variable_bound ( & self , variable : usize ) -> bool {
pub fn are_all_variable_bound < ' a > (
let mut found = false ;
& self ,
self . lookup_always_bound_variables ( & mut | v | {
variables : impl IntoIterator < Item = & ' a usize > ,
if v = = variable {
) -> bool {
found = true ;
let bound = self . always_bound_variables ( ) ;
}
variables . into_iter ( ) . all ( | v | bound . contains ( v ) )
} ) ;
found
}
}
}
}
@ -459,10 +473,17 @@ pub enum PlanExpression {
}
}
impl PlanExpression {
impl PlanExpression {
pub fn lookup_used_variables ( & self , callback : & mut impl FnMut ( usize ) ) {
/// Returns variables that are used in the expression
pub fn used_variables ( & self ) -> BTreeSet < usize > {
let mut set = BTreeSet ::default ( ) ;
self . add_used_variables ( & mut set ) ;
set
}
pub fn add_used_variables ( & self , set : & mut BTreeSet < usize > ) {
match self {
match self {
Self ::Variable ( v ) | Self ::Bound ( v ) = > {
Self ::Variable ( v ) | Self ::Bound ( v ) = > {
callback ( * v ) ;
set . insert ( * v ) ;
}
}
Self ::Constant ( _ )
Self ::Constant ( _ )
| Self ::Rand
| Self ::Rand
@ -518,7 +539,7 @@ impl PlanExpression {
| Self ::DurationCast ( e )
| Self ::DurationCast ( e )
| Self ::YearMonthDurationCast ( e )
| Self ::YearMonthDurationCast ( e )
| Self ::DayTimeDurationCast ( e )
| Self ::DayTimeDurationCast ( e )
| Self ::StringCast ( e ) = > e . lookup_used_variables ( callback ) ,
| Self ::StringCast ( e ) = > e . add_used_variables ( set ) ,
Self ::Or ( a , b )
Self ::Or ( a , b )
| Self ::And ( a , b )
| Self ::And ( a , b )
| Self ::Equal ( a , b )
| Self ::Equal ( a , b )
@ -541,31 +562,31 @@ impl PlanExpression {
| Self ::SameTerm ( a , b )
| Self ::SameTerm ( a , b )
| Self ::SubStr ( a , b , None )
| Self ::SubStr ( a , b , None )
| Self ::Regex ( a , b , None ) = > {
| Self ::Regex ( a , b , None ) = > {
a . lookup_used_variables ( callback ) ;
a . add_used_variables ( set ) ;
b . lookup_used_variables ( callback ) ;
b . add_used_variables ( set ) ;
}
}
Self ::If ( a , b , c )
Self ::If ( a , b , c )
| Self ::SubStr ( a , b , Some ( c ) )
| Self ::SubStr ( a , b , Some ( c ) )
| Self ::Regex ( a , b , Some ( c ) )
| Self ::Regex ( a , b , Some ( c ) )
| Self ::Replace ( a , b , c , None )
| Self ::Replace ( a , b , c , None )
| Self ::Triple ( a , b , c ) = > {
| Self ::Triple ( a , b , c ) = > {
a . lookup_used_variables ( callback ) ;
a . add_used_variables ( set ) ;
b . lookup_used_variables ( callback ) ;
b . add_used_variables ( set ) ;
c . lookup_used_variables ( callback ) ;
c . add_used_variables ( set ) ;
}
}
Self ::Replace ( a , b , c , Some ( d ) ) = > {
Self ::Replace ( a , b , c , Some ( d ) ) = > {
a . lookup_used_variables ( callback ) ;
a . add_used_variables ( set ) ;
b . lookup_used_variables ( callback ) ;
b . add_used_variables ( set ) ;
c . lookup_used_variables ( callback ) ;
c . add_used_variables ( set ) ;
d . lookup_used_variables ( callback ) ;
d . add_used_variables ( set ) ;
}
}
Self ::Concat ( es ) | Self ::Coalesce ( es ) | Self ::CustomFunction ( _ , es ) = > {
Self ::Concat ( es ) | Self ::Coalesce ( es ) | Self ::CustomFunction ( _ , es ) = > {
for e in es {
for e in es {
e . lookup_used_variables ( callback ) ;
e . add_used_variables ( set ) ;
}
}
}
}
Self ::Exists ( e ) = > {
Self ::Exists ( e ) = > {
e . lookup_used_variables ( callback ) ;
e . add_used_variables ( set ) ;
}
}
}
}
}
}