Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 903d306

Browse files
committedJan 2, 2024
Analysis prototype
1 parent ac13e7d commit 903d306

10 files changed

+1099
-367
lines changed
 
+329
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
// Copyright Materialize, Inc. and contributors. All rights reserved.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the LICENSE file.
5+
//
6+
// As of the Change Date specified in that file, in accordance with
7+
// the Business Source License, use of this software will be governed
8+
// by the Apache License, Version 2.0.
9+
10+
//! Traits and types for reusable expression analysis
11+
12+
use mz_expr::MirRelationExpr;
13+
14+
pub use common::{Derived, DerivedBuilder};
15+
16+
pub use arity::Arity;
17+
pub use subtree::SubtreeSize;
18+
pub use types::RelationType;
19+
20+
/// An analysis that can be applied bottom-up to a `MirRelationExpr`.
21+
pub trait Analysis: 'static {
22+
/// The type of value this analysis associates with an expression.
23+
type Value;
24+
/// Announce any depencies this analysis has on other analyses.
25+
///
26+
/// The method should invoke `builder.depend_on(foo)` for each other
27+
/// analysis `foo` this analysis depends upon.
28+
fn announce_dependencies(_builder: &mut DerivedBuilder) {}
29+
/// The analysis value derived for an expression, given other derivations.
30+
///
31+
/// The other derivations include full derivations of this expression and
32+
/// all children for announced dependencies, and derivations of children
33+
/// for this analysis (but not for the expression itself, yet to be done).
34+
fn derive(expr: &MirRelationExpr, results: &[Self::Value], depends: &Derived) -> Self::Value;
35+
}
36+
37+
/// Types common across multiple analyses
38+
pub mod common {
39+
40+
use std::any::{Any, TypeId};
41+
use std::collections::BTreeMap;
42+
43+
use mz_expr::LocalId;
44+
use mz_expr::MirRelationExpr;
45+
46+
use super::subtree::SubtreeSize;
47+
use super::Analysis;
48+
49+
/// Container for analysis state and binding context.
50+
#[derive(Default)]
51+
#[allow(missing_debug_implementations)]
52+
pub struct Derived {
53+
/// A record of active analyses and their results, indexed by their type id.
54+
analyses: BTreeMap<TypeId, Box<dyn AnalysisBundle>>,
55+
/// Analyses ordered where each depends only on strictly prior analyses.
56+
order: Vec<TypeId>,
57+
/// Map from local identifier to result offset for analysis values.
58+
bindings: BTreeMap<LocalId, usize>,
59+
}
60+
61+
impl Derived {
62+
/// Return the analysis results derived so far.
63+
pub fn results<A: Analysis>(&self) -> Option<&[A::Value]> {
64+
let type_id = TypeId::of::<Bundle<A>>();
65+
if let Some(bundle) = self.analyses.get(&type_id) {
66+
if let Some(bundle) = bundle.as_any().downcast_ref::<Bundle<A>>() {
67+
return Some(&bundle.results[..]);
68+
}
69+
}
70+
None
71+
}
72+
/// Bindings from local identifiers to result offsets for analysis values.
73+
pub fn bindings(&self) -> &BTreeMap<LocalId, usize> {
74+
&self.bindings
75+
}
76+
/// Result offsets for the state of a various number of children of the current expression.
77+
///
78+
/// The integers are the zero-offset locations in the `SubtreeSize` analysis,
79+
/// which if absent will cause the method to return `None`. The order of the children
80+
/// is descending, from last child to first, because of how the information is laid out,
81+
/// and the non-reversibility of the look-ups.
82+
///
83+
/// It is an error to call this method with more children than expression has
84+
pub fn children_of_rev<'a>(
85+
&'a self,
86+
start: usize,
87+
count: usize,
88+
) -> Option<impl Iterator<Item = usize> + 'a> {
89+
if let Some(sizes) = self.results::<SubtreeSize>() {
90+
let offset = 1;
91+
Some((0..count).scan(offset, move |offset, _| {
92+
let result = start - *offset;
93+
*offset += sizes[result];
94+
Some(result)
95+
}))
96+
} else {
97+
None
98+
}
99+
}
100+
}
101+
102+
/// A builder wrapper to accumulate announced dependencies and construct default state.
103+
#[allow(missing_debug_implementations)]
104+
#[derive(Default)]
105+
pub struct DerivedBuilder {
106+
result: Derived,
107+
}
108+
109+
impl DerivedBuilder {
110+
/// Announces a dependence on an analysis `A`.
111+
///
112+
/// This ensures that `A` will be performed, and before any analysis that
113+
/// invokes this method.
114+
pub fn require<A: Analysis>(&mut self) {
115+
let type_id = TypeId::of::<Bundle<A>>();
116+
if !self.result.analyses.contains_key(&type_id) {
117+
A::announce_dependencies(self);
118+
if self.result.analyses.contains_key(&type_id) {
119+
// panic!("Cyclic dependency detected: {:?}");
120+
}
121+
self.result.order.push(type_id);
122+
self.result.analyses.insert(
123+
type_id,
124+
Box::new(Bundle::<A> {
125+
results: Vec::new(),
126+
}),
127+
);
128+
}
129+
}
130+
/// Complete the building, and return a usable `Derivation`.
131+
pub fn visit(self, expr: &MirRelationExpr) -> Derived {
132+
let mut result = self.result;
133+
134+
// A stack of expressions to process (`Ok`) and let bindings to fill (`Err`).
135+
let mut todo = vec![Ok(expr)];
136+
// Expressions in reverse post-order: each expression, followed by its children in reverse order.
137+
// We will reverse this to get the post order, but must form it in reverse.
138+
let mut rev_post_order = Vec::new();
139+
while let Some(command) = todo.pop() {
140+
match command {
141+
// An expression to visit.
142+
Ok(expr) => {
143+
match expr {
144+
MirRelationExpr::Let { id, value, body } => {
145+
todo.push(Ok(value));
146+
todo.push(Err(*id));
147+
todo.push(Ok(body));
148+
}
149+
MirRelationExpr::LetRec {
150+
ids, values, body, ..
151+
} => {
152+
for (id, value) in ids.iter().zip(values).rev() {
153+
todo.push(Ok(value));
154+
todo.push(Err(*id));
155+
}
156+
todo.push(Ok(body));
157+
}
158+
_ => {
159+
todo.extend(expr.children().map(Ok));
160+
}
161+
}
162+
rev_post_order.push(expr);
163+
}
164+
// A local id to install
165+
Err(local_id) => {
166+
// Capture the *remaining* work, which we'll need to flip around.
167+
let prior = result.bindings.insert(local_id, rev_post_order.len());
168+
assert!(prior.is_none());
169+
}
170+
}
171+
}
172+
// Flip the offsets now that we know a length.
173+
for value in result.bindings.values_mut() {
174+
*value = rev_post_order.len() - *value - 1;
175+
}
176+
// Visit the pre-order in reverse order: post-order.
177+
while let Some(expr) = rev_post_order.pop() {
178+
// Apply each analysis to `expr` in order.
179+
for id in result.order.iter() {
180+
if let Some(mut bundle) = result.analyses.remove(id) {
181+
bundle.analyse(expr, &result);
182+
result.analyses.insert(*id, bundle);
183+
}
184+
}
185+
}
186+
187+
result
188+
}
189+
}
190+
191+
/// An abstraction for an analysis and associated state.
192+
trait AnalysisBundle: Any {
193+
fn analyse(&mut self, expr: &MirRelationExpr, depends: &Derived);
194+
/// Upcasts `self` to a `&dyn Any`.
195+
///
196+
/// NOTE: This is required until <https://github.com/rust-lang/rfcs/issues/2765> is fixed
197+
fn as_any(&self) -> &dyn std::any::Any;
198+
}
199+
200+
/// A wrapper for analysis state.
201+
struct Bundle<A: Analysis> {
202+
results: Vec<A::Value>,
203+
}
204+
205+
impl<A: Analysis> AnalysisBundle for Bundle<A> {
206+
fn analyse(&mut self, expr: &MirRelationExpr, depends: &Derived) {
207+
let value = A::derive(expr, &self.results[..], depends);
208+
self.results.push(value);
209+
}
210+
fn as_any(&self) -> &dyn std::any::Any {
211+
self
212+
}
213+
}
214+
}
215+
216+
/// Expression subtree sizes
217+
pub mod subtree {
218+
219+
use super::{Analysis, Derived};
220+
use mz_expr::MirRelationExpr;
221+
222+
/// Analysis that determines the size in child expressions of relation expressions.
223+
#[derive(Debug)]
224+
pub struct SubtreeSize;
225+
226+
impl Analysis for SubtreeSize {
227+
type Value = usize;
228+
229+
fn derive(
230+
expr: &MirRelationExpr,
231+
results: &[Self::Value],
232+
_depends: &Derived,
233+
) -> Self::Value {
234+
match expr {
235+
MirRelationExpr::Constant { .. } | MirRelationExpr::Get { .. } => 1,
236+
_ => {
237+
let n = results.len();
238+
let mut offset = 1;
239+
for _ in expr.children() {
240+
offset += results[n - offset];
241+
}
242+
offset
243+
}
244+
}
245+
}
246+
}
247+
}
248+
249+
/// Expression arities
250+
mod arity {
251+
252+
use super::subtree::SubtreeSize;
253+
use super::{Analysis, Derived, DerivedBuilder};
254+
use mz_expr::MirRelationExpr;
255+
256+
/// Analysis that determines the number of columns of relation expressions.
257+
#[derive(Debug)]
258+
pub struct Arity;
259+
260+
impl Analysis for Arity {
261+
type Value = usize;
262+
263+
fn announce_dependencies(builder: &mut DerivedBuilder) {
264+
builder.require::<SubtreeSize>();
265+
}
266+
267+
fn derive(
268+
expr: &MirRelationExpr,
269+
results: &[Self::Value],
270+
depends: &Derived,
271+
) -> Self::Value {
272+
let mut offsets = Vec::new();
273+
let position = results.len();
274+
for child in depends
275+
.children_of_rev(position, expr.children().count())
276+
.expect("SubtreeSize missing")
277+
{
278+
offsets.push(results[child]);
279+
}
280+
offsets.reverse();
281+
assert_eq!(expr.arity_with_input_arities(offsets.iter()), expr.arity());
282+
expr.arity_with_input_arities(offsets.iter())
283+
}
284+
}
285+
}
286+
287+
/// Expression types
288+
mod types {
289+
290+
use super::subtree::SubtreeSize;
291+
use super::{Analysis, Derived, DerivedBuilder};
292+
use mz_expr::MirRelationExpr;
293+
use mz_repr::ColumnType;
294+
295+
/// Analysis that determines the type of relation expressions.
296+
#[derive(Debug)]
297+
pub struct RelationType;
298+
299+
impl Analysis for RelationType {
300+
type Value = Option<Vec<ColumnType>>;
301+
302+
fn announce_dependencies(builder: &mut DerivedBuilder) {
303+
builder.require::<SubtreeSize>();
304+
}
305+
306+
fn derive(
307+
expr: &MirRelationExpr,
308+
results: &[Self::Value],
309+
depends: &Derived,
310+
) -> Self::Value {
311+
let mut offsets = Vec::new();
312+
let position = results.len();
313+
for child in depends
314+
.children_of_rev(position, expr.children().count())
315+
.expect("SubtreeSize missing")
316+
{
317+
offsets.push(&results[child]);
318+
}
319+
320+
if offsets.iter().all(|o| o.is_some()) {
321+
let input_cols = offsets.into_iter().rev().map(|o| o.as_ref().unwrap());
322+
let subtree_column_types = expr.try_col_with_input_cols(input_cols);
323+
subtree_column_types.ok()
324+
} else {
325+
None
326+
}
327+
}
328+
}
329+
}

‎src/transform/src/attribute/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ mod relation_type;
2525
mod subtree_size;
2626
mod unique_keys;
2727

28+
pub mod analysis;
29+
pub use analysis::{Analysis, Derived, DerivedBuilder};
30+
2831
// Attributes should have shortened paths when exported.
2932
pub use arity::Arity;
3033
pub use cardinality::Cardinality;
@@ -53,9 +56,7 @@ pub trait Attribute {
5356
fn handle_env_tasks(&mut self) {}
5457

5558
/// The attribute ids of all other attributes that this attribute depends on.
56-
fn add_dependencies(builder: &mut DerivedAttributesBuilder)
57-
where
58-
Self: Sized;
59+
fn add_dependencies(builder: &mut DerivedAttributesBuilder);
5960

6061
/// Attributes for each subexpression, visited in post-order.
6162
fn get_results(&self) -> &Vec<Self::Value>;

‎src/transform/src/equivalence_propagation.rs

+647-223
Large diffs are not rendered by default.

‎test/sqllogictest/cardinality.slt

+22-22
Original file line numberDiff line numberDiff line change
@@ -298,21 +298,21 @@ Explained Query:
298298
ArrangeBy keys=[[#0]]
299299
Union
300300
Negate
301-
CrossJoin type=differential
302-
ArrangeBy keys=[[]]
303-
Get l1
304-
ArrangeBy keys=[[]]
305-
Distinct project=[]
306-
Project ()
307-
Get l0
308-
Project (#1, #2)
309-
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
301+
Project (#0, #1)
302+
Join on=(#2 = least(#0, #1) AND #3 = greatest(#0, #1)) type=differential
303+
ArrangeBy keys=[[greatest(#0, #1), least(#0, #1)]]
304+
Get l0
305+
ArrangeBy keys=[[#1, #0]]
306+
Distinct project=[least(#0, #1), greatest(#0, #1)]
307+
Get l1
308+
Get l0
310309
Get l1
311310
cte l1 =
312311
Project (#1, #2)
313-
Get l0
312+
Filter (3 = least(#1, #2)) AND (4 = greatest(#1, #2))
313+
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
314314
cte l0 =
315-
Filter (3 = least(#1, #2)) AND (4 = greatest(#1, #2))
315+
Project (#1, #2)
316316
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
317317

318318
Used Indexes:
@@ -412,21 +412,21 @@ Explained Query:
412412
ArrangeBy keys=[[#0]]
413413
Union
414414
Negate
415-
CrossJoin type=differential
416-
ArrangeBy keys=[[]]
417-
Get l1
418-
ArrangeBy keys=[[]]
419-
Distinct project=[]
420-
Project ()
421-
Get l0
422-
Project (#1, #2)
423-
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
415+
Project (#0, #1)
416+
Join on=(#2 = least(#0, #1) AND #3 = greatest(#0, #1)) type=differential
417+
ArrangeBy keys=[[greatest(#0, #1), least(#0, #1)]]
418+
Get l0
419+
ArrangeBy keys=[[#1, #0]]
420+
Distinct project=[least(#0, #1), greatest(#0, #1)]
421+
Get l1
422+
Get l0
424423
Get l1
425424
cte l1 =
426425
Project (#1, #2)
427-
Get l0
426+
Filter (3 = least(#1, #2)) AND (4 = greatest(#1, #2))
427+
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
428428
cte l0 =
429-
Filter (3 = least(#1, #2)) AND (4 = greatest(#1, #2))
429+
Project (#1, #2)
430430
ReadIndex on=person_knows_person person_knows_person_person1id_person2id=[*** full scan ***]
431431

432432
Used Indexes:

‎test/sqllogictest/github-9782.slt

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Explained Query:
8787
Project (#1, #2) // { arity: 2 }
8888
Get l0 // { arity: 3 }
8989
Get l1 // { arity: 3 }
90-
Filter (#0 = #1) AND (#0 = #2) // { arity: 3 }
90+
Filter (#0 = #1) // { arity: 3 }
9191
Get l0 // { arity: 3 }
9292
With
9393
cte l1 =

‎test/sqllogictest/ldbc_bi.slt

+69-75
Original file line numberDiff line numberDiff line change
@@ -2178,10 +2178,12 @@ Explained Query:
21782178
Negate // { arity: 16 }
21792179
Distinct project=[#0{id}..=#15{email}] // { arity: 16 }
21802180
Project (#0..=#15) // { arity: 16 }
2181-
Get l1 // { arity: 17 }
2182-
Distinct project=[#0{id}, #1{url}, #2{partofcontinentid}, #3{id}, #4{name}, #5{url}, #6{creationdate}, #7{id}, #8{firstname}, #9{lastname}, #10{gender}, #11{birthday}, #12{locationip}, #13{browserused}, #14{speaks}, #15{email}] // { arity: 16 }
2183-
Get l0 // { arity: 16 }
2184-
ArrangeBy keys=[[#0{id}, #1{url}, #2{partofcontinentid}, #3{id}, #4{name}, #5{url}, #6{creationdate}, #7{id}, #8{firstname}, #9{lastname}, #10{gender}, #11{birthday}, #12{locationip}, #13{browserused}, #14{speaks}, #15{email}]] // { arity: 16 }
2181+
Filter (#0{id} = #0{id}) AND (#3{id} = #3{id}) // { arity: 17 }
2182+
Get l1 // { arity: 17 }
2183+
Distinct project=[#0{id}..=#15{email}] // { arity: 16 }
2184+
Filter (#0{id} = #0{id}) AND (#3{id} = #3{id}) // { arity: 16 }
2185+
Get l0 // { arity: 16 }
2186+
ArrangeBy keys=[[#0{id}..=#15{email}]] // { arity: 16 }
21852187
Get l0 // { arity: 16 }
21862188
cte l1 =
21872189
Project (#0..=#15, #17) // { arity: 17 }
@@ -2540,44 +2542,44 @@ Explained Query:
25402542
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
25412543
Get l3 // { arity: 2 }
25422544
ArrangeBy keys=[[#1, #0]] // { arity: 2 }
2543-
Distinct project=[#0, #1] // { arity: 2 }
2544-
Project (#2, #3) // { arity: 2 }
2545-
Get l2 // { arity: 5 }
2545+
Distinct project=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] // { arity: 2 }
2546+
Project (#0, #1) // { arity: 2 }
2547+
Get l2 // { arity: 3 }
25462548
Get l3 // { arity: 2 }
2547-
Project (#0, #1, #4) // { arity: 3 }
2548-
Get l2 // { arity: 5 }
2549+
Get l2 // { arity: 3 }
25492550
Constant // { arity: 2 }
25502551
- (1450, 0)
25512552
cte l3 =
25522553
Project (#1, #2) // { arity: 2 }
25532554
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
25542555
cte l2 =
2555-
Join on=(#2 = least(#0{person1id}, #1{person2id}) AND #3 = greatest(#0{person1id}, #1{person2id})) type=differential // { arity: 5 }
2556-
implementation
2557-
%1[#1, #0]UKK » %0:person_knows_person[greatest(#0, #1), least(#0, #1)]KK
2558-
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
2559-
Project (#1, #2) // { arity: 2 }
2560-
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
2561-
ArrangeBy keys=[[#1, #0]] // { arity: 3 }
2562-
Reduce group_by=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] aggregates=[sum(case when (#2{parentmessageid}) IS NULL then 10 else 5 end)] // { arity: 3 }
2563-
Project (#0..=#2) // { arity: 3 }
2564-
Join on=(#3{containerforumid} = #4{containerforumid} = #5{id}) type=delta // { arity: 6 }
2565-
implementation
2566-
%0:l1 » %1[#0]UKA » %2[#0]UKA
2567-
%1 » %2[#0]UKA » %0:l1[#3]KA
2568-
%2 » %1[#0]UKA » %0:l1[#3]KA
2569-
ArrangeBy keys=[[#3{containerforumid}]] // { arity: 4 }
2570-
Get l1 // { arity: 4 }
2571-
ArrangeBy keys=[[#0{containerforumid}]] // { arity: 1 }
2572-
Distinct project=[#0{containerforumid}] // { arity: 1 }
2573-
Project (#3) // { arity: 1 }
2574-
Filter (#3{containerforumid}) IS NOT NULL // { arity: 4 }
2575-
Get l1 // { arity: 4 }
2576-
ArrangeBy keys=[[#0{id}]] // { arity: 1 }
2577-
Distinct project=[#0{id}] // { arity: 1 }
2578-
Project (#1) // { arity: 1 }
2579-
Filter (#0{creationdate} <= 2012-11-10 00:00:00 UTC) AND (#0{creationdate} >= 2012-11-06 00:00:00 UTC) AND (#1{id}) IS NOT NULL // { arity: 4 }
2580-
ReadIndex on=forum forum_id=[*** full scan ***] // { arity: 4 }
2556+
Project (#0, #1, #4) // { arity: 3 }
2557+
Join on=(#2 = least(#0{person1id}, #1{person2id}) AND #3 = greatest(#0{person1id}, #1{person2id})) type=differential // { arity: 5 }
2558+
implementation
2559+
%1[#1, #0]UKK » %0:person_knows_person[greatest(#0, #1), least(#0, #1)]KK
2560+
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
2561+
Project (#1, #2) // { arity: 2 }
2562+
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
2563+
ArrangeBy keys=[[#1, #0]] // { arity: 3 }
2564+
Reduce group_by=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] aggregates=[sum(case when (#2{parentmessageid}) IS NULL then 10 else 5 end)] // { arity: 3 }
2565+
Project (#0..=#2) // { arity: 3 }
2566+
Join on=(#3{containerforumid} = #4{containerforumid} = #5{id}) type=delta // { arity: 6 }
2567+
implementation
2568+
%0:l1 » %1[#0]UKA » %2[#0]UKA
2569+
%1 » %2[#0]UKA » %0:l1[#3]KA
2570+
%2 » %1[#0]UKA » %0:l1[#3]KA
2571+
ArrangeBy keys=[[#3{containerforumid}]] // { arity: 4 }
2572+
Get l1 // { arity: 4 }
2573+
ArrangeBy keys=[[#0{containerforumid}]] // { arity: 1 }
2574+
Distinct project=[#0{containerforumid}] // { arity: 1 }
2575+
Project (#3) // { arity: 1 }
2576+
Filter (#3{containerforumid}) IS NOT NULL // { arity: 4 }
2577+
Get l1 // { arity: 4 }
2578+
ArrangeBy keys=[[#0{id}]] // { arity: 1 }
2579+
Distinct project=[#0{id}] // { arity: 1 }
2580+
Project (#1) // { arity: 1 }
2581+
Filter (#0{creationdate} <= 2012-11-10 00:00:00 UTC) AND (#0{creationdate} >= 2012-11-06 00:00:00 UTC) AND (#1{id}) IS NOT NULL // { arity: 4 }
2582+
ReadIndex on=forum forum_id=[*** full scan ***] // { arity: 4 }
25812583
cte l1 =
25822584
Project (#0, #1, #3, #4) // { arity: 4 }
25832585
Join on=(#2{containerforumid} = #5{containerforumid} = #6{id}) type=delta // { arity: 7 }
@@ -2962,42 +2964,42 @@ Explained Query:
29622964
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
29632965
Get l3 // { arity: 2 }
29642966
ArrangeBy keys=[[#1, #0]] // { arity: 2 }
2965-
Distinct project=[#0, #1] // { arity: 2 }
2966-
Project (#2, #3) // { arity: 2 }
2967-
Get l2 // { arity: 5 }
2967+
Distinct project=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] // { arity: 2 }
2968+
Project (#0, #1) // { arity: 2 }
2969+
Get l2 // { arity: 3 }
29682970
Get l3 // { arity: 2 }
2969-
Project (#0, #1, #4) // { arity: 3 }
2970-
Get l2 // { arity: 5 }
2971+
Get l2 // { arity: 3 }
29712972
cte l3 =
29722973
Project (#1, #2) // { arity: 2 }
29732974
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
29742975
cte l2 =
2975-
Join on=(#2 = least(#0{person1id}, #1{person2id}) AND #3 = greatest(#0{person1id}, #1{person2id})) type=differential // { arity: 5 }
2976-
implementation
2977-
%1[#1, #0]UKK » %0:person_knows_person[greatest(#0, #1), least(#0, #1)]KK
2978-
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
2979-
Project (#1, #2) // { arity: 2 }
2980-
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
2981-
ArrangeBy keys=[[#1, #0]] // { arity: 3 }
2982-
Reduce group_by=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] aggregates=[sum(case when (#2{parentmessageid}) IS NULL then 10 else 5 end)] // { arity: 3 }
2983-
Project (#0..=#2) // { arity: 3 }
2984-
Join on=(#3{containerforumid} = #4{containerforumid} = #5{id}) type=delta // { arity: 6 }
2985-
implementation
2986-
%0:l1 » %1[#0]UKA » %2[#0]UKA
2987-
%1 » %2[#0]UKA » %0:l1[#3]KA
2988-
%2 » %1[#0]UKA » %0:l1[#3]KA
2989-
ArrangeBy keys=[[#3{containerforumid}]] // { arity: 4 }
2990-
Get l1 // { arity: 4 }
2991-
ArrangeBy keys=[[#0{containerforumid}]] // { arity: 1 }
2992-
Distinct project=[#0{containerforumid}] // { arity: 1 }
2993-
Project (#3) // { arity: 1 }
2994-
Filter (#3{containerforumid}) IS NOT NULL // { arity: 4 }
2995-
Get l1 // { arity: 4 }
2996-
ArrangeBy keys=[[#0{id}]] // { arity: 1 }
2997-
Distinct project=[#0{id}] // { arity: 1 }
2998-
Project (#1) // { arity: 1 }
2999-
Filter (#0{creationdate} <= 2012-11-10 00:00:00 UTC) AND (#0{creationdate} >= 2012-11-06 00:00:00 UTC) AND (#1{id}) IS NOT NULL // { arity: 4 }
3000-
ReadIndex on=forum forum_id=[*** full scan ***] // { arity: 4 }
2976+
Project (#0, #1, #4) // { arity: 3 }
2977+
Join on=(#2 = least(#0{person1id}, #1{person2id}) AND #3 = greatest(#0{person1id}, #1{person2id})) type=differential // { arity: 5 }
2978+
implementation
2979+
%1[#1, #0]UKK » %0:person_knows_person[greatest(#0, #1), least(#0, #1)]KK
2980+
ArrangeBy keys=[[greatest(#0{person1id}, #1{person2id}), least(#0{person1id}, #1{person2id})]] // { arity: 2 }
2981+
Project (#1, #2) // { arity: 2 }
2982+
ReadIndex on=person_knows_person person_knows_person_person1id=[*** full scan ***] // { arity: 3 }
2983+
ArrangeBy keys=[[#1, #0]] // { arity: 3 }
2984+
Reduce group_by=[least(#0{person1id}, #1{person2id}), greatest(#0{person1id}, #1{person2id})] aggregates=[sum(case when (#2{parentmessageid}) IS NULL then 10 else 5 end)] // { arity: 3 }
2985+
Project (#0..=#2) // { arity: 3 }
2986+
Join on=(#3{containerforumid} = #4{containerforumid} = #5{id}) type=delta // { arity: 6 }
2987+
implementation
2988+
%0:l1 » %1[#0]UKA » %2[#0]UKA
2989+
%1 » %2[#0]UKA » %0:l1[#3]KA
2990+
%2 » %1[#0]UKA » %0:l1[#3]KA
2991+
ArrangeBy keys=[[#3{containerforumid}]] // { arity: 4 }
2992+
Get l1 // { arity: 4 }
2993+
ArrangeBy keys=[[#0{containerforumid}]] // { arity: 1 }
2994+
Distinct project=[#0{containerforumid}] // { arity: 1 }
2995+
Project (#3) // { arity: 1 }
2996+
Filter (#3{containerforumid}) IS NOT NULL // { arity: 4 }
2997+
Get l1 // { arity: 4 }
2998+
ArrangeBy keys=[[#0{id}]] // { arity: 1 }
2999+
Distinct project=[#0{id}] // { arity: 1 }
3000+
Project (#1) // { arity: 1 }
3001+
Filter (#0{creationdate} <= 2012-11-10 00:00:00 UTC) AND (#0{creationdate} >= 2012-11-06 00:00:00 UTC) AND (#1{id}) IS NOT NULL // { arity: 4 }
3002+
ReadIndex on=forum forum_id=[*** full scan ***] // { arity: 4 }
30013003
cte l1 =
30023004
Project (#0, #1, #3, #4) // { arity: 4 }
30033005
Join on=(#2{containerforumid} = #5{containerforumid} = #6{id}) type=delta // { arity: 7 }
@@ -4464,22 +4466,14 @@ Explained Query:
44644466
cte l11 =
44654467
Distinct project=[#0..=#5] // { arity: 6 }
44664468
Union // { arity: 6 }
4467-
<<<<<<< HEAD
44684469
Project (#0..=#2, #4, #3, #5) // { arity: 6 }
44694470
Map (false, 0, 0) // { arity: 6 }
44704471
Distinct project=[#0..=#2{personid}] // { arity: 3 }
44714472
Union // { arity: 3 }
44724473
Project (#1, #0, #0) // { arity: 3 }
4473-
=======
4474-
Project (#0, #1, #1, #3, #2, #4) // { arity: 6 }
4475-
Map (false, 0, 0) // { arity: 5 }
4476-
Distinct project=[#0, #1{personid}] // { arity: 2 }
4477-
Union // { arity: 2 }
4478-
Project (#1, #0) // { arity: 2 }
4479-
>>>>>>> 0eca4aec38 (WIP checkin)
44804474
Map (10995116285979, false) // { arity: 2 }
44814475
Get l10 // { arity: 0 }
4482-
Project (#1, #0) // { arity: 2 }
4476+
Project (#1, #0, #0) // { arity: 3 }
44834477
Map (true) // { arity: 2 }
44844478
CrossJoin type=differential // { arity: 1 }
44854479
implementation

‎test/sqllogictest/transform/column_knowledge.slt

+1-1
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ SELECT f1, f2, f1 + f2 FROM c0;
624624
----
625625
Explained Query:
626626
Return // { arity: 3, types: "(integer, integer, integer)" }
627-
Map ((#0 + #1)) // { arity: 3, types: "(integer, integer, integer)" }
627+
Map (8) // { arity: 3, types: "(integer, integer, integer)" }
628628
Get l0 // { arity: 2, types: "(integer, integer)" }
629629
With Mutually Recursive [recursion_limit=1]
630630
cte l0 =

‎test/sqllogictest/transform/lifting.slt

+22-32
Original file line numberDiff line numberDiff line change
@@ -638,38 +638,33 @@ explain with(arity, join_impls) select min(a) from t_pk where a between 38 and 1
638638
Explained Query:
639639
Return // { arity: 1 }
640640
Union // { arity: 1 }
641-
Get l1 // { arity: 1 }
641+
Get l0 // { arity: 1 }
642642
Map (null) // { arity: 1 }
643643
Union // { arity: 0 }
644644
Negate // { arity: 0 }
645645
Project () // { arity: 0 }
646-
Get l1 // { arity: 1 }
646+
Get l0 // { arity: 1 }
647647
Constant // { arity: 0 }
648648
- ()
649649
With
650-
cte l1 =
650+
cte l0 =
651651
Reduce aggregates=[min(#0)] // { arity: 1 }
652652
Project (#0) // { arity: 1 }
653653
Join on=(#0 = #1) type=differential // { arity: 2 }
654654
implementation
655-
%0:t_pk[#0]UKiif » %1[#0]Kiif
655+
%0:t_pk[#0]UKiif » %1[#0]UKiif
656656
ArrangeBy keys=[[#0]] // { arity: 1 }
657657
Project (#0) // { arity: 1 }
658658
Filter (#0 <= 195) AND (#0 >= 38) // { arity: 2 }
659659
ReadStorage materialize.public.t_pk // { arity: 2 }
660660
ArrangeBy keys=[[#0]] // { arity: 1 }
661-
Union // { arity: 1 }
662-
Project (#0) // { arity: 1 }
663-
Get l0 // { arity: 2 }
664-
Map (error("more than one record produced in subquery")) // { arity: 1 }
665-
Project () // { arity: 0 }
666-
Filter (#0 > 1) // { arity: 1 }
667-
Reduce aggregates=[count(*)] // { arity: 1 }
668-
Project () // { arity: 0 }
669-
Get l0 // { arity: 2 }
670-
cte l0 =
671-
Filter (#0 = 1308) // { arity: 2 }
672-
ReadStorage materialize.public.t // { arity: 2 }
661+
Map (error("more than one record produced in subquery")) // { arity: 1 }
662+
Project () // { arity: 0 }
663+
Filter (#0 > 1) // { arity: 1 }
664+
Reduce aggregates=[count(*)] // { arity: 1 }
665+
Project () // { arity: 0 }
666+
Filter (#0 = 1308) // { arity: 2 }
667+
ReadStorage materialize.public.t // { arity: 2 }
673668

674669
Source materialize.public.t
675670
filter=((#0 = 1308))
@@ -684,38 +679,33 @@ explain with(arity, join_impls) select min(a) from t where a between 38 and 195
684679
Explained Query:
685680
Return // { arity: 1 }
686681
Union // { arity: 1 }
687-
Get l1 // { arity: 1 }
682+
Get l0 // { arity: 1 }
688683
Map (null) // { arity: 1 }
689684
Union // { arity: 0 }
690685
Negate // { arity: 0 }
691686
Project () // { arity: 0 }
692-
Get l1 // { arity: 1 }
687+
Get l0 // { arity: 1 }
693688
Constant // { arity: 0 }
694689
- ()
695690
With
696-
cte l1 =
691+
cte l0 =
697692
Reduce aggregates=[min(#0)] // { arity: 1 }
698693
Project (#0) // { arity: 1 }
699694
Join on=(#0 = #1) type=differential // { arity: 2 }
700695
implementation
701-
%0:t[#0]Kiif » %1[#0]Kiif
696+
%1[#0]UK » %0:t[#0]Kiif
702697
ArrangeBy keys=[[#0]] // { arity: 1 }
703698
Project (#0) // { arity: 1 }
704699
Filter (#0 <= 195) AND (#0 >= 38) // { arity: 2 }
705700
ReadStorage materialize.public.t // { arity: 2 }
706701
ArrangeBy keys=[[#0]] // { arity: 1 }
707-
Union // { arity: 1 }
708-
Project (#0) // { arity: 1 }
709-
Get l0 // { arity: 2 }
710-
Map (error("more than one record produced in subquery")) // { arity: 1 }
711-
Project () // { arity: 0 }
712-
Filter (#0 > 1) // { arity: 1 }
713-
Reduce aggregates=[count(*)] // { arity: 1 }
714-
Project () // { arity: 0 }
715-
Get l0 // { arity: 2 }
716-
cte l0 =
717-
Filter (#0 = 1308) // { arity: 2 }
718-
ReadStorage materialize.public.t // { arity: 2 }
702+
Map (error("more than one record produced in subquery")) // { arity: 1 }
703+
Project () // { arity: 0 }
704+
Filter (#0 > 1) // { arity: 1 }
705+
Reduce aggregates=[count(*)] // { arity: 1 }
706+
Project () // { arity: 0 }
707+
Filter (#0 = 1308) // { arity: 2 }
708+
ReadStorage materialize.public.t // { arity: 2 }
719709

720710
EOF
721711

‎test/sqllogictest/transform/predicate_pushdown.slt

+2-8
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,8 @@ EXPLAIN WITH(arity, join_impls)
8787
(SELECT a, a+1 as b FROM y))
8888
WHERE b = 3 AND c = 3
8989
----
90-
Explained Query:
91-
Filter (#1 = 3) AND (#2 = 3) // { arity: 3 }
92-
Map ((#0 + 1), (#1 + 1)) // { arity: 3 }
93-
ReadStorage materialize.public.y // { arity: 1 }
94-
95-
Source materialize.public.y
96-
filter=((3 = #1) AND (3 = (#1 + 1)))
97-
map=((#0 + 1))
90+
Explained Query (fast path):
91+
Constant <empty>
9892

9993
EOF
10094

‎test/sqllogictest/uniqueness_propagation_filter.slt

+2-2
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ query T multiline
212212
EXPLAIN WITH(arity, join_impls) SELECT DISTINCT f1 + 1 , f2 FROM v1 WHERE f1 + 1 = f3;
213213
----
214214
Explained Query:
215-
Distinct project=[(#0 + 1), #1] // { arity: 2 }
216-
Project (#0, #1) // { arity: 2 }
215+
Distinct project=[#1, #0] // { arity: 2 }
216+
Project (#1, #2) // { arity: 2 }
217217
Filter (#2 = (#0 + 1)) // { arity: 3 }
218218
ReadIndex on=v1 v1_primary_idx=[*** full scan ***] // { arity: 3 }
219219

0 commit comments

Comments
 (0)
Please sign in to comment.