1use crate::model::pattern::{ObjectPattern, PredicatePattern, SubjectPattern, TriplePattern};
7use crate::model::*;
8use crate::query::algebra::{
9 AlgebraTriplePattern, Expression, GraphPattern, OrderExpression, Query, QueryForm,
10 SelectVariables, TermPattern,
11};
12use crate::OxirsError;
13
14pub fn convert_triple_pattern(pattern: &AlgebraTriplePattern) -> TriplePattern {
17 convert_algebra_triple_pattern(pattern)
19}
20
21pub fn convert_algebra_triple_pattern(pattern: &AlgebraTriplePattern) -> TriplePattern {
24 let subject = match &pattern.subject {
25 TermPattern::NamedNode(nn) => Some(SubjectPattern::NamedNode(nn.clone())),
26 TermPattern::BlankNode(bn) => Some(SubjectPattern::BlankNode(bn.clone())),
27 TermPattern::Variable(v) => Some(SubjectPattern::Variable(v.clone())),
28 TermPattern::Literal(_) => None, TermPattern::QuotedTriple(qt) => Some(SubjectPattern::QuotedTriple(qt.clone())),
30 };
31
32 let predicate = match &pattern.predicate {
33 TermPattern::NamedNode(nn) => Some(PredicatePattern::NamedNode(nn.clone())),
34 TermPattern::Variable(v) => Some(PredicatePattern::Variable(v.clone())),
35 _ => None, };
37
38 let object = match &pattern.object {
39 TermPattern::NamedNode(nn) => Some(ObjectPattern::NamedNode(nn.clone())),
40 TermPattern::BlankNode(bn) => Some(ObjectPattern::BlankNode(bn.clone())),
41 TermPattern::Literal(lit) => Some(ObjectPattern::Literal(lit.clone())),
42 TermPattern::Variable(v) => Some(ObjectPattern::Variable(v.clone())),
43 TermPattern::QuotedTriple(qt) => Some(ObjectPattern::QuotedTriple(qt.clone())),
44 };
45
46 TriplePattern::new(subject, predicate, object)
47}
48
49pub fn convert_to_algebra_pattern(
52 pattern: &TriplePattern,
53) -> Result<AlgebraTriplePattern, OxirsError> {
54 let subject = match pattern.subject() {
55 Some(SubjectPattern::NamedNode(nn)) => TermPattern::NamedNode(nn.clone()),
56 Some(SubjectPattern::BlankNode(bn)) => TermPattern::BlankNode(bn.clone()),
57 Some(SubjectPattern::Variable(v)) => TermPattern::Variable(v.clone()),
58 Some(SubjectPattern::QuotedTriple(qt)) => TermPattern::QuotedTriple(qt.clone()),
59 None => {
60 return Err(OxirsError::Query(
61 "Subject pattern is required in algebra representation".to_string(),
62 ))
63 }
64 };
65
66 let predicate = match pattern.predicate() {
67 Some(PredicatePattern::NamedNode(nn)) => TermPattern::NamedNode(nn.clone()),
68 Some(PredicatePattern::Variable(v)) => TermPattern::Variable(v.clone()),
69 None => {
70 return Err(OxirsError::Query(
71 "Predicate pattern is required in algebra representation".to_string(),
72 ))
73 }
74 };
75
76 let object = match pattern.object() {
77 Some(ObjectPattern::NamedNode(nn)) => TermPattern::NamedNode(nn.clone()),
78 Some(ObjectPattern::BlankNode(bn)) => TermPattern::BlankNode(bn.clone()),
79 Some(ObjectPattern::Literal(lit)) => TermPattern::Literal(lit.clone()),
80 Some(ObjectPattern::Variable(v)) => TermPattern::Variable(v.clone()),
81 Some(ObjectPattern::QuotedTriple(qt)) => TermPattern::QuotedTriple(qt.clone()),
82 None => {
83 return Err(OxirsError::Query(
84 "Object pattern is required in algebra representation".to_string(),
85 ))
86 }
87 };
88
89 Ok(AlgebraTriplePattern::new(subject, predicate, object))
90}
91
92#[derive(Debug, Clone)]
94pub enum ExecutionPlan {
95 TripleScan {
97 pattern: crate::model::pattern::TriplePattern,
98 },
99 HashJoin {
101 left: Box<ExecutionPlan>,
102 right: Box<ExecutionPlan>,
103 join_vars: Vec<Variable>,
104 },
105 Filter {
107 input: Box<ExecutionPlan>,
108 condition: Expression,
109 },
110 Project {
112 input: Box<ExecutionPlan>,
113 vars: Vec<Variable>,
114 },
115 Sort {
117 input: Box<ExecutionPlan>,
118 order_by: Vec<OrderExpression>,
119 },
120 Limit {
122 input: Box<ExecutionPlan>,
123 limit: usize,
124 offset: usize,
125 },
126 Union {
128 left: Box<ExecutionPlan>,
129 right: Box<ExecutionPlan>,
130 },
131 Distinct { input: Box<ExecutionPlan> },
133}
134
135pub struct QueryPlanner;
137
138impl QueryPlanner {
139 pub fn new() -> Self {
141 QueryPlanner
142 }
143
144 pub fn plan_query(&self, query: &Query) -> Result<ExecutionPlan, OxirsError> {
146 match &query.form {
147 QueryForm::Select {
148 where_clause,
149 variables,
150 distinct,
151 order_by,
152 limit,
153 offset,
154 ..
155 } => {
156 let mut plan = self.plan_graph_pattern(where_clause)?;
157
158 if let SelectVariables::Specific(vars) = variables {
160 plan = ExecutionPlan::Project {
161 input: Box::new(plan),
162 vars: vars.clone(),
163 };
164 }
165
166 if *distinct {
168 plan = ExecutionPlan::Distinct {
169 input: Box::new(plan),
170 };
171 }
172
173 if !order_by.is_empty() {
175 plan = ExecutionPlan::Sort {
176 input: Box::new(plan),
177 order_by: order_by.clone(),
178 };
179 }
180
181 if let Some(limit_val) = limit {
183 plan = ExecutionPlan::Limit {
184 input: Box::new(plan),
185 limit: *limit_val,
186 offset: *offset,
187 };
188 } else if *offset > 0 {
189 plan = ExecutionPlan::Limit {
190 input: Box::new(plan),
191 limit: usize::MAX,
192 offset: *offset,
193 };
194 }
195
196 Ok(plan)
197 }
198 _ => Err(OxirsError::Query(
199 "Only SELECT queries are currently supported".to_string(),
200 )),
201 }
202 }
203
204 fn plan_graph_pattern(&self, pattern: &GraphPattern) -> Result<ExecutionPlan, OxirsError> {
206 match pattern {
207 GraphPattern::Bgp(patterns) => {
208 if patterns.is_empty() {
209 return Err(OxirsError::Query("Empty basic graph pattern".to_string()));
210 }
211
212 let mut plan = ExecutionPlan::TripleScan {
214 pattern: convert_triple_pattern(&patterns[0]),
215 };
216
217 for pattern in &patterns[1..] {
219 let right_plan = ExecutionPlan::TripleScan {
220 pattern: convert_triple_pattern(pattern),
221 };
222
223 let join_vars = self.find_join_variables(&plan, &right_plan);
225
226 plan = ExecutionPlan::HashJoin {
227 left: Box::new(plan),
228 right: Box::new(right_plan),
229 join_vars,
230 };
231 }
232
233 Ok(plan)
234 }
235 GraphPattern::Filter { expr, inner } => {
236 let inner_plan = self.plan_graph_pattern(inner)?;
237 Ok(ExecutionPlan::Filter {
238 input: Box::new(inner_plan),
239 condition: expr.clone(),
240 })
241 }
242 GraphPattern::Union(left, right) => {
243 let left_plan = self.plan_graph_pattern(left)?;
244 let right_plan = self.plan_graph_pattern(right)?;
245 Ok(ExecutionPlan::Union {
246 left: Box::new(left_plan),
247 right: Box::new(right_plan),
248 })
249 }
250 _ => Err(OxirsError::Query(
251 "Graph pattern not yet supported".to_string(),
252 )),
253 }
254 }
255
256 fn find_join_variables(&self, _left: &ExecutionPlan, _right: &ExecutionPlan) -> Vec<Variable> {
258 Vec::new()
260 }
261}
262
263impl Default for QueryPlanner {
264 fn default() -> Self {
265 Self::new()
266 }
267}