├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── lesson-1 ├── Cargo.toml └── src │ ├── lib.rs │ ├── s01_define_the_ir.rs │ ├── s02_create_a_plan.rs │ ├── s03_heuristics.rs │ ├── s04_memo.rs │ ├── s05_apply_rule_again.rs │ └── s06_new_repr.rs └── src ├── ir2.rs ├── ir2 └── rel_node.rs ├── ir3.rs ├── ir3 └── rel_node.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "optimizer-blog-lesson-1" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["lesson-1"] 3 | resolver = "2" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # optimizer-lesson 2 | 3 | This is the code for the [Lessons Learned from Building a Query Optimizer](https://www.skyzh.dev/tags/optimizer-lesson/) series. 4 | -------------------------------------------------------------------------------- /lesson-1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "optimizer-blog-lesson-1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /lesson-1/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod s01_define_the_ir; 2 | pub use s01_define_the_ir::*; 3 | pub mod s02_create_a_plan; 4 | pub use s02_create_a_plan::*; 5 | pub mod s03_heuristics; 6 | pub use s03_heuristics::*; 7 | pub mod s04_memo; 8 | pub use s04_memo::*; 9 | pub mod s05_apply_rule_again; 10 | pub use s05_apply_rule_again::*; 11 | pub mod s06_new_repr; 12 | -------------------------------------------------------------------------------- /lesson-1/src/s01_define_the_ir.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 4 | pub struct TableId(pub usize); 5 | 6 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 7 | pub struct Scan { 8 | pub table: TableId, 9 | } 10 | 11 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 12 | pub struct Join { 13 | pub left: Arc, 14 | pub right: Arc, 15 | pub cond: Arc, 16 | } 17 | 18 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 19 | pub struct Filter { 20 | pub child: Arc, 21 | pub predicate: Arc, 22 | } 23 | 24 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 25 | pub struct EqPred { 26 | pub left: Arc, 27 | pub right: Arc, 28 | } 29 | 30 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 31 | pub struct ColumnRefPred { 32 | pub column: usize, 33 | } 34 | 35 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 36 | pub struct ConstPred { 37 | pub value: i64, 38 | } 39 | 40 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 41 | pub enum RelNode { 42 | Scan(Scan), 43 | Join(Join), 44 | Filter(Filter), 45 | Eq(EqPred), 46 | ColumnRef(ColumnRefPred), 47 | Const(ConstPred), 48 | } 49 | 50 | pub fn scan(table: TableId) -> RelNode { 51 | RelNode::Scan(Scan { table }) 52 | } 53 | 54 | pub fn filter(child: impl Into>, cond: impl Into>) -> RelNode { 55 | RelNode::Filter(Filter { 56 | child: child.into(), 57 | predicate: cond.into(), 58 | }) 59 | } 60 | 61 | pub fn join( 62 | left: impl Into>, 63 | right: impl Into>, 64 | cond: impl Into>, 65 | ) -> RelNode { 66 | RelNode::Join(Join { 67 | left: left.into(), 68 | right: right.into(), 69 | cond: cond.into(), 70 | }) 71 | } 72 | 73 | pub fn eq_pred(left: impl Into>, right: impl Into>) -> RelNode { 74 | RelNode::Eq(EqPred { 75 | left: left.into(), 76 | right: right.into(), 77 | }) 78 | } 79 | 80 | pub fn column_ref_pred(idx: usize) -> RelNode { 81 | RelNode::ColumnRef(ColumnRefPred { column: idx }) 82 | } 83 | 84 | pub fn const_pred(value: i64) -> RelNode { 85 | RelNode::Const(ConstPred { value }) 86 | } 87 | -------------------------------------------------------------------------------- /lesson-1/src/s02_create_a_plan.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use super::*; 4 | 5 | pub fn plan() -> RelNode { 6 | filter( 7 | join( 8 | scan(TableId(0)), 9 | scan(TableId(1)), 10 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 11 | ), 12 | eq_pred(column_ref_pred(2), const_pred(3)), 13 | ) 14 | } 15 | 16 | pub fn join_commute(node: Arc) -> Option> { 17 | if let RelNode::Join(ref a) = &*node { 18 | // TODO: rewrite the condition 19 | return Some(join(a.right.clone(), a.left.clone(), a.cond.clone()).into()); 20 | } 21 | None 22 | } 23 | 24 | pub fn join_assoc(node: Arc) -> Option> { 25 | if let RelNode::Join(ref a) = &*node { 26 | if let RelNode::Join(b) = &*a.left { 27 | return Some( 28 | join( 29 | b.left.clone(), 30 | join(b.right.clone(), a.right.clone(), a.cond.clone()), 31 | b.cond.clone(), 32 | ) 33 | .into(), 34 | ); 35 | } 36 | } 37 | None 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | 44 | #[test] 45 | fn test_rule_apply() { 46 | let initial = join( 47 | scan(TableId(0)), 48 | scan(TableId(1)), 49 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 50 | ); 51 | let expected = join( 52 | scan(TableId(1)), 53 | scan(TableId(0)), 54 | // obviously, the predicate is wrong... but that's fine for now 55 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 56 | ); 57 | assert_eq!(join_commute(Arc::new(initial)).unwrap().as_ref(), &expected); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lesson-1/src/s03_heuristics.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use super::*; 4 | 5 | // Recursive access and rewrite 6 | pub fn apply_rule_bottom_up( 7 | node: Arc, 8 | rule: impl Fn(Arc) -> Option>, 9 | ) -> Arc { 10 | fn apply_rule_bottom_up_inner( 11 | node: Arc, 12 | rule: &impl Fn(Arc) -> Option>, 13 | ) -> Arc { 14 | let mut children = Vec::new(); 15 | for child in node.children() { 16 | let child = apply_rule_bottom_up_inner(child, rule); 17 | children.push(child); 18 | } 19 | let rel = Arc::new(node.clone_with_children(children)); 20 | rule(rel.clone()).unwrap_or_else(|| rel) 21 | } 22 | apply_rule_bottom_up_inner(node, &rule) 23 | } 24 | 25 | impl Scan { 26 | pub fn children(&self) -> Vec> { 27 | vec![] 28 | } 29 | 30 | pub fn clone_with_children(&self, children: Vec>) -> Self { 31 | let _ = children; 32 | Self { 33 | table: self.table.clone(), 34 | } 35 | } 36 | } 37 | 38 | impl Filter { 39 | pub fn children(&self) -> Vec> { 40 | vec![self.child.clone(), self.predicate.clone()] 41 | } 42 | 43 | pub fn clone_with_children(&self, children: Vec>) -> Self { 44 | Self { 45 | child: children[0].clone(), 46 | predicate: children[1].clone(), 47 | } 48 | } 49 | } 50 | 51 | impl Join { 52 | pub fn children(&self) -> Vec> { 53 | vec![self.left.clone(), self.right.clone(), self.cond.clone()] 54 | } 55 | 56 | pub fn clone_with_children(&self, children: Vec>) -> Self { 57 | Self { 58 | left: children[0].clone(), 59 | right: children[1].clone(), 60 | cond: children[2].clone(), 61 | } 62 | } 63 | } 64 | 65 | impl EqPred { 66 | pub fn children(&self) -> Vec> { 67 | vec![self.left.clone(), self.right.clone()] 68 | } 69 | 70 | pub fn clone_with_children(&self, children: Vec>) -> Self { 71 | Self { 72 | left: children[0].clone(), 73 | right: children[1].clone(), 74 | } 75 | } 76 | } 77 | 78 | impl ColumnRefPred { 79 | pub fn children(&self) -> Vec> { 80 | vec![] 81 | } 82 | 83 | pub fn clone_with_children(&self, children: Vec>) -> Self { 84 | let _ = children; 85 | Self { 86 | column: self.column, 87 | } 88 | } 89 | } 90 | 91 | impl ConstPred { 92 | pub fn children(&self) -> Vec> { 93 | vec![] 94 | } 95 | 96 | pub fn clone_with_children(&self, children: Vec>) -> Self { 97 | let _ = children; 98 | Self { value: self.value } 99 | } 100 | } 101 | 102 | impl RelNode { 103 | pub fn children(&self) -> Vec> { 104 | match self { 105 | RelNode::Scan(scan) => scan.children(), 106 | RelNode::Join(join) => join.children(), 107 | RelNode::Filter(filter) => filter.children(), 108 | RelNode::Eq(eq) => eq.children(), 109 | RelNode::ColumnRef(column_ref) => column_ref.children(), 110 | RelNode::Const(const_pred) => const_pred.children(), 111 | } 112 | } 113 | 114 | pub fn clone_with_children(&self, children: Vec>) -> Self { 115 | match self { 116 | RelNode::Scan(scan) => RelNode::Scan(scan.clone_with_children(children)), 117 | RelNode::Join(join) => RelNode::Join(join.clone_with_children(children)), 118 | RelNode::Filter(filter) => RelNode::Filter(filter.clone_with_children(children)), 119 | RelNode::Eq(eq) => RelNode::Eq(eq.clone_with_children(children)), 120 | RelNode::ColumnRef(column_ref) => { 121 | RelNode::ColumnRef(column_ref.clone_with_children(children)) 122 | } 123 | RelNode::Const(const_pred) => RelNode::Const(const_pred.clone_with_children(children)), 124 | } 125 | } 126 | } 127 | 128 | #[cfg(test)] 129 | mod tests { 130 | use super::*; 131 | 132 | #[test] 133 | fn test_bottom_up() { 134 | let initial = join( 135 | scan(TableId(0)), 136 | join( 137 | scan(TableId(1)), 138 | scan(TableId(2)), 139 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 140 | ), 141 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 142 | ); 143 | let expected = join( 144 | join( 145 | scan(TableId(2)), 146 | scan(TableId(1)), 147 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 148 | ), 149 | scan(TableId(0)), 150 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 151 | ); 152 | assert_eq!( 153 | apply_rule_bottom_up(Arc::new(initial), join_commute).as_ref(), 154 | &expected 155 | ); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /lesson-1/src/s04_memo.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, sync::Arc}; 2 | 3 | use super::*; 4 | 5 | pub type MemoScan = Scan; 6 | pub type MemoColumnRefPred = ColumnRefPred; 7 | pub type MemoConstPred = ConstPred; 8 | 9 | #[derive(Copy, Debug, Clone, Hash, Eq, PartialEq)] 10 | pub struct GroupId(usize); 11 | 12 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 13 | pub struct MemoJoin { 14 | pub left: GroupId, 15 | pub right: GroupId, 16 | pub cond: GroupId, 17 | } 18 | 19 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 20 | pub struct MemoFilter { 21 | pub child: GroupId, 22 | pub predicate: GroupId, 23 | } 24 | 25 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 26 | pub struct MemoEqPred { 27 | pub left: GroupId, 28 | pub right: GroupId, 29 | } 30 | 31 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 32 | pub enum MemoRelNode { 33 | Scan(MemoScan), 34 | Join(MemoJoin), 35 | Filter(MemoFilter), 36 | Eq(MemoEqPred), 37 | ColumnRef(MemoColumnRefPred), 38 | Const(MemoConstPred), 39 | } 40 | 41 | pub struct Memo { 42 | groups: Vec>, 43 | expr_to_group: HashMap, 44 | } 45 | 46 | impl Memo { 47 | pub fn add_expr(&mut self, expr: MemoRelNode) -> GroupId { 48 | if let Some(group_id) = self.get_group(expr.clone()) { 49 | return group_id; 50 | } 51 | let id = GroupId(self.groups.len()); 52 | self.groups.push(vec![expr.clone()]); 53 | self.expr_to_group.insert(expr, id); 54 | id 55 | } 56 | 57 | pub fn get_group(&self, expr: MemoRelNode) -> Option { 58 | self.expr_to_group.get(&expr).copied() 59 | } 60 | 61 | pub fn new() -> Self { 62 | Self { 63 | groups: vec![], 64 | expr_to_group: HashMap::new(), 65 | } 66 | } 67 | 68 | pub fn dump(&self) { 69 | for (i, group) in self.groups.iter().enumerate() { 70 | println!("Group {}", i); 71 | for expr in group { 72 | println!(" {:?}", expr); 73 | } 74 | } 75 | } 76 | 77 | pub fn get_all_exprs_in_group(&self, group: GroupId) -> Vec { 78 | self.groups[group.0].iter().cloned().collect() 79 | } 80 | 81 | pub fn merge_group(&mut self, group1: GroupId, group2: GroupId) -> GroupId { 82 | unimplemented!() 83 | } 84 | 85 | pub fn add_expr_to_group(&mut self, group: GroupId, expr: MemoRelNode) { 86 | unimplemented!() 87 | } 88 | } 89 | 90 | pub fn memorize_rel(memo: &mut Memo, rel: Arc) -> GroupId { 91 | let rel = match &*rel { 92 | RelNode::Scan(scan) => MemoRelNode::Scan(scan.clone()), 93 | RelNode::Join(join) => MemoRelNode::Join(MemoJoin { 94 | left: memorize_rel(memo, join.left.clone()), 95 | right: memorize_rel(memo, join.right.clone()), 96 | cond: memorize_rel(memo, join.cond.clone()), 97 | }), 98 | RelNode::Filter(filter) => MemoRelNode::Filter(MemoFilter { 99 | child: memorize_rel(memo, filter.child.clone()), 100 | predicate: memorize_rel(memo, filter.predicate.clone()), 101 | }), 102 | RelNode::Eq(eq) => MemoRelNode::Eq(MemoEqPred { 103 | left: memorize_rel(memo, eq.left.clone()), 104 | right: memorize_rel(memo, eq.right.clone()), 105 | }), 106 | RelNode::ColumnRef(column_ref) => MemoRelNode::ColumnRef(column_ref.clone()), 107 | RelNode::Const(const_pred) => MemoRelNode::Const(const_pred.clone()), 108 | // ... doesn't seem maintainable 109 | }; 110 | memo.add_expr(rel) 111 | } 112 | 113 | pub fn generate_one_binding(memo: &Memo, group: GroupId) -> Arc { 114 | let expr = &memo.groups[group.0][0]; 115 | match expr { 116 | MemoRelNode::Scan(scan) => Arc::new(RelNode::Scan(scan.clone())), 117 | MemoRelNode::Join(join) => Arc::new(RelNode::Join(Join { 118 | left: generate_one_binding(memo, join.left), 119 | right: generate_one_binding(memo, join.right), 120 | cond: generate_one_binding(memo, join.cond), 121 | })), 122 | MemoRelNode::Filter(filter) => Arc::new(RelNode::Filter(Filter { 123 | child: generate_one_binding(memo, filter.child), 124 | predicate: generate_one_binding(memo, filter.predicate), 125 | })), 126 | MemoRelNode::Eq(eq) => Arc::new(RelNode::Eq(EqPred { 127 | left: generate_one_binding(memo, eq.left), 128 | right: generate_one_binding(memo, eq.right), 129 | })), 130 | MemoRelNode::ColumnRef(column_ref) => Arc::new(RelNode::ColumnRef(column_ref.clone())), 131 | MemoRelNode::Const(const_pred) => Arc::new(RelNode::Const(const_pred.clone())), 132 | // ... doesn't seem maintainable 133 | } 134 | } 135 | 136 | #[cfg(test)] 137 | mod tests { 138 | use super::*; 139 | 140 | #[test] 141 | fn test_memorize_rel() { 142 | let mut memo = Memo { 143 | groups: vec![], 144 | expr_to_group: HashMap::new(), 145 | }; 146 | 147 | let rel = join( 148 | // Do a self-join 149 | filter(scan(TableId(0)), eq_pred(column_ref_pred(1), const_pred(3))), 150 | filter(scan(TableId(0)), eq_pred(column_ref_pred(1), const_pred(3))), 151 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 152 | ); 153 | 154 | let group_id = memorize_rel(&mut memo, Arc::new(rel.clone())); 155 | memo.dump(); 156 | 157 | assert_eq!(memo.groups.len(), 8); 158 | assert_eq!(generate_one_binding(&memo, group_id).as_ref(), &rel); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /lesson-1/src/s05_apply_rule_again.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use super::*; 4 | 5 | pub type BindScan = Scan; 6 | pub type BindColumnRefPred = ColumnRefPred; 7 | pub type BindConstPred = ConstPred; 8 | 9 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 10 | pub struct BindJoin { 11 | pub left: Arc, 12 | pub right: Arc, 13 | pub cond: Arc, 14 | } 15 | 16 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 17 | pub struct BindFilter { 18 | pub child: Arc, 19 | pub predicate: Arc, 20 | } 21 | 22 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 23 | pub struct BindEqPred { 24 | pub left: Arc, 25 | pub right: Arc, 26 | } 27 | 28 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 29 | pub enum BindRelNode { 30 | Scan(BindScan), 31 | Join(BindJoin), 32 | Filter(BindFilter), 33 | Eq(BindEqPred), 34 | ColumnRef(BindColumnRefPred), 35 | Const(BindConstPred), 36 | Group(GroupId), 37 | } 38 | 39 | fn join_commute_memo(node: Arc) -> Option> { 40 | if let BindRelNode::Join(ref a) = &*node { 41 | // TODO: rewrite the condition 42 | return Some(Arc::new(BindRelNode::Join(BindJoin { 43 | right: a.left.clone(), 44 | left: a.right.clone(), 45 | cond: a.cond.clone(), 46 | }))); 47 | } 48 | None 49 | } 50 | 51 | fn join_assoc_memo(node: Arc) -> Option> { 52 | if let BindRelNode::Join(ref a) = &*node { 53 | if let BindRelNode::Join(b) = &*a.left { 54 | return Some(Arc::new(BindRelNode::Join(BindJoin { 55 | left: b.left.clone(), 56 | right: Arc::new(BindRelNode::Join(BindJoin { 57 | left: b.right.clone(), 58 | right: a.right.clone(), 59 | cond: a.cond.clone(), 60 | })), 61 | cond: b.cond.clone(), 62 | }))); 63 | } 64 | } 65 | None 66 | } 67 | 68 | pub fn apply_join_commute_rules_on_node(memo: &mut Memo, group: GroupId, node: MemoRelNode) { 69 | if let MemoRelNode::Join(node) = node { 70 | let binding = BindJoin { 71 | left: Arc::new(BindRelNode::Group(node.left)), 72 | right: Arc::new(BindRelNode::Group(node.right)), 73 | cond: Arc::new(BindRelNode::Group(node.cond)), 74 | }; 75 | let applied = join_commute_memo(Arc::new(BindRelNode::Join(binding))).unwrap(); 76 | add_binding_to_memo(memo, group, applied); 77 | } 78 | } 79 | 80 | pub fn apply_join_assoc_rules_on_node(memo: &mut Memo, group: GroupId, node: MemoRelNode) { 81 | if let MemoRelNode::Join(node1) = node { 82 | for expr in memo.get_all_exprs_in_group(node1.left) { 83 | if let MemoRelNode::Join(node2) = expr { 84 | let binding = BindJoin { 85 | left: Arc::new(BindRelNode::Join(BindJoin { 86 | left: Arc::new(BindRelNode::Group(node2.left)), 87 | right: Arc::new(BindRelNode::Group(node2.right)), 88 | cond: Arc::new(BindRelNode::Group(node2.cond)), 89 | })), 90 | right: Arc::new(BindRelNode::Group(node1.right)), 91 | cond: Arc::new(BindRelNode::Group(node1.cond)), 92 | }; 93 | let applied = join_assoc_memo(Arc::new(BindRelNode::Join(binding))).unwrap(); 94 | add_binding_to_memo(memo, group, applied); 95 | } 96 | } 97 | } 98 | } 99 | 100 | pub fn add_binding_to_memo(memo: &mut Memo, group: GroupId, node: Arc) -> GroupId { 101 | fn add_binding_to_memo_inner(memo: &mut Memo, node: Arc) -> GroupId { 102 | let node = match &*node { 103 | BindRelNode::Scan(scan) => MemoRelNode::Scan(scan.clone()), 104 | BindRelNode::Join(join) => { 105 | let left = add_binding_to_memo_inner(memo, join.left.clone()); 106 | let right = add_binding_to_memo_inner(memo, join.right.clone()); 107 | let cond = add_binding_to_memo_inner(memo, join.cond.clone()); 108 | MemoRelNode::Join(MemoJoin { left, right, cond }) 109 | } 110 | BindRelNode::Filter(filter) => { 111 | let child = add_binding_to_memo_inner(memo, filter.child.clone()); 112 | let predicate = add_binding_to_memo_inner(memo, filter.predicate.clone()); 113 | MemoRelNode::Filter(MemoFilter { child, predicate }) 114 | } 115 | BindRelNode::Eq(eq) => { 116 | let left = add_binding_to_memo_inner(memo, eq.left.clone()); 117 | let right = add_binding_to_memo_inner(memo, eq.right.clone()); 118 | MemoRelNode::Eq(MemoEqPred { left, right }) 119 | } 120 | BindRelNode::ColumnRef(column_ref) => MemoRelNode::ColumnRef(column_ref.clone()), 121 | BindRelNode::Const(constant) => MemoRelNode::Const(constant.clone()), 122 | BindRelNode::Group(group) => return *group, 123 | }; 124 | memo.add_expr(node.clone()) 125 | } 126 | let new_group = add_binding_to_memo_inner(memo, node); 127 | if group != new_group { 128 | memo.merge_group(group, new_group) 129 | } else { 130 | group 131 | } 132 | } 133 | 134 | // define repr and core, how to find a way to do both easily? 135 | -------------------------------------------------------------------------------- /lesson-1/src/s06_new_repr.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::GroupId; 4 | 5 | #[derive(Clone)] 6 | pub struct TableId(pub usize); 7 | 8 | #[derive(Clone)] 9 | pub enum RelNodeType { 10 | Scan, 11 | Filter, 12 | Join, 13 | Eq, 14 | ColumnRef, 15 | Const, 16 | } 17 | 18 | pub enum RelAttrType { 19 | TableId(TableId), 20 | ColumnRef(usize), 21 | Const(i64), 22 | None, 23 | } 24 | 25 | pub struct RelNode { 26 | pub typ: RelNodeType, 27 | pub children: Vec>, 28 | pub data: Arc, 29 | } 30 | 31 | pub struct MemoRelNode { 32 | pub typ: RelNodeType, 33 | pub children: Vec, 34 | pub data: RelAttrType, 35 | } 36 | 37 | pub enum BindRelNode { 38 | RelNode { 39 | typ: RelNodeType, 40 | children: Vec>, 41 | data: Arc, 42 | }, 43 | Group(GroupId), 44 | } 45 | 46 | pub enum RelNodeMatcher { 47 | Match { 48 | typ: RelNodeType, 49 | children: Vec, 50 | }, 51 | Any, 52 | } 53 | 54 | pub fn scan(table: TableId) -> RelNode { 55 | RelNode { 56 | typ: RelNodeType::Scan, 57 | children: vec![], 58 | data: Arc::new(RelAttrType::TableId(table)), 59 | } 60 | } 61 | 62 | pub fn filter(child: impl Into>, cond: impl Into>) -> RelNode { 63 | RelNode { 64 | typ: RelNodeType::Filter, 65 | children: vec![child.into(), cond.into()], 66 | data: Arc::new(RelAttrType::None), 67 | } 68 | } 69 | 70 | pub fn join( 71 | left: impl Into>, 72 | right: impl Into>, 73 | cond: impl Into>, 74 | ) -> RelNode { 75 | RelNode { 76 | typ: RelNodeType::Filter, 77 | children: vec![left.into(), right.into(), cond.into()], 78 | data: Arc::new(RelAttrType::None), 79 | } 80 | } 81 | 82 | pub fn eq_pred(left: impl Into>, right: impl Into>) -> RelNode { 83 | RelNode { 84 | typ: RelNodeType::Eq, 85 | children: vec![left.into(), right.into()], 86 | data: Arc::new(RelAttrType::None), 87 | } 88 | } 89 | 90 | pub fn column_ref_pred(idx: usize) -> RelNode { 91 | RelNode { 92 | typ: RelNodeType::ColumnRef, 93 | children: vec![], 94 | data: Arc::new(RelAttrType::ColumnRef(idx)), 95 | } 96 | } 97 | 98 | pub fn const_pred(value: i64) -> RelNode { 99 | RelNode { 100 | typ: RelNodeType::Const, 101 | children: vec![], 102 | data: Arc::new(RelAttrType::Const(value)), 103 | } 104 | } 105 | 106 | pub struct Scan(Arc); 107 | 108 | impl Scan { 109 | pub fn try_from_relnode(node: Arc) -> Option { 110 | let RelNodeType::Scan = node.typ else { 111 | return None; 112 | }; 113 | Some(Self(node)) 114 | } 115 | 116 | pub fn into_relnode(self) -> Arc { 117 | self.0 118 | } 119 | 120 | pub fn table(&self) -> TableId { 121 | match &*self.0.data { 122 | RelAttrType::TableId(table) => table.clone(), 123 | _ => panic!("not a scan node"), 124 | } 125 | } 126 | } 127 | 128 | pub struct Filter(Arc); 129 | 130 | impl Filter { 131 | pub fn try_from_relnode(node: Arc) -> Option { 132 | let RelNodeType::Filter = node.typ else { 133 | return None; 134 | }; 135 | Some(Self(node)) 136 | } 137 | 138 | pub fn into_relnode(self) -> Arc { 139 | self.0 140 | } 141 | 142 | pub fn child(&self) -> Arc { 143 | self.0.children[0].clone() 144 | } 145 | 146 | pub fn cond(&self) -> Arc { 147 | self.0.children[1].clone() 148 | } 149 | } 150 | 151 | pub struct Join(Arc); 152 | 153 | impl Join { 154 | pub fn try_from_relnode(node: Arc) -> Option { 155 | let RelNodeType::Join = node.typ else { 156 | return None; 157 | }; 158 | Some(Self(node)) 159 | } 160 | 161 | pub fn into_relnode(self) -> Arc { 162 | self.0 163 | } 164 | 165 | pub fn left(&self) -> Arc { 166 | self.0.children[0].clone() 167 | } 168 | 169 | pub fn right(&self) -> Arc { 170 | self.0.children[1].clone() 171 | } 172 | 173 | pub fn cond(&self) -> Arc { 174 | self.0.children[2].clone() 175 | } 176 | } 177 | 178 | pub struct Eq(Arc); 179 | 180 | impl Eq { 181 | pub fn try_from_relnode(node: Arc) -> Option { 182 | let RelNodeType::Eq = node.typ else { 183 | return None; 184 | }; 185 | Some(Self(node)) 186 | } 187 | 188 | pub fn into_relnode(self) -> Arc { 189 | self.0 190 | } 191 | 192 | pub fn left(&self) -> Arc { 193 | self.0.children[0].clone() 194 | } 195 | 196 | pub fn right(&self) -> Arc { 197 | self.0.children[1].clone() 198 | } 199 | } 200 | 201 | pub struct ColumnRef(Arc); 202 | 203 | impl ColumnRef { 204 | pub fn try_from_relnode(node: Arc) -> Option { 205 | let RelNodeType::ColumnRef = node.typ else { 206 | return None; 207 | }; 208 | Some(Self(node)) 209 | } 210 | 211 | pub fn idx(&self) -> usize { 212 | match &*self.0.data { 213 | RelAttrType::ColumnRef(idx) => *idx, 214 | _ => panic!("not a column ref node"), 215 | } 216 | } 217 | 218 | pub fn into_relnode(self) -> Arc { 219 | self.0 220 | } 221 | } 222 | 223 | pub struct Const(Arc); 224 | 225 | impl Const { 226 | pub fn try_from_relnode(node: Arc) -> Option { 227 | let RelNodeType::Const = node.typ else { 228 | return None; 229 | }; 230 | Some(Self(node)) 231 | } 232 | 233 | pub fn value(&self) -> i64 { 234 | match &*self.0.data { 235 | RelAttrType::Const(value) => *value, 236 | _ => panic!("not a const node"), 237 | } 238 | } 239 | 240 | pub fn into_relnode(self) -> Arc { 241 | self.0 242 | } 243 | } 244 | 245 | pub fn plan() -> RelNode { 246 | filter( 247 | join( 248 | scan(TableId(0)), 249 | scan(TableId(1)), 250 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 251 | ), 252 | eq_pred(column_ref_pred(2), const_pred(3)), 253 | ) 254 | } 255 | -------------------------------------------------------------------------------- /src/ir2.rs: -------------------------------------------------------------------------------- 1 | mod rel_node; 2 | use std::sync::Arc; 3 | 4 | pub use rel_node::*; 5 | 6 | pub fn plan() -> RelNode { 7 | filter( 8 | join( 9 | scan(TableId(0)), 10 | scan(TableId(1)), 11 | eq_pred(column_ref_pred(1), column_ref_pred(3)), 12 | ), 13 | eq_pred(column_ref_pred(2), const_pred(3)), 14 | ) 15 | } 16 | 17 | pub fn join_assoc(node: Arc) -> Option> { 18 | if let Some(a) = Join::try_from_relnode(node) { 19 | if let Some(b) = Join::try_from_relnode(a.left()) { 20 | return Some(join(b.left(), join(b.right(), a.right(), a.cond()), b.cond()).into()); 21 | } 22 | } 23 | None 24 | } 25 | 26 | pub fn apply_rule_bottom_up(node: &RelNode, rule: impl Fn(&RelNode) -> Option) -> RelNode { 27 | let mut children = Vec::new(); 28 | for child in &node.children { 29 | let child = apply_rule_bottom_up(child, &rule); 30 | children.push(Arc::new(child)); 31 | } 32 | RelNode { 33 | typ: node.typ.clone(), 34 | children, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ir2/rel_node.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | #[derive(Clone)] 4 | pub struct TableId(pub usize); 5 | 6 | #[derive(Clone)] 7 | pub enum RelNodeType { 8 | Scan(TableId), 9 | Filter, 10 | Join, 11 | Eq, 12 | ColumnRef(usize), 13 | Const(i64), 14 | } 15 | 16 | pub struct RelNode { 17 | pub typ: RelNodeType, 18 | pub children: Vec>, 19 | } 20 | 21 | pub fn scan(table: TableId) -> RelNode { 22 | RelNode { 23 | typ: RelNodeType::Scan(table), 24 | children: vec![], 25 | } 26 | } 27 | 28 | pub fn filter(child: impl Into>, cond: impl Into>) -> RelNode { 29 | RelNode { 30 | typ: RelNodeType::Filter, 31 | children: vec![child.into(), cond.into()], 32 | } 33 | } 34 | 35 | pub fn join(left: impl Into>, right: impl Into>, cond: impl Into>) -> RelNode { 36 | RelNode { 37 | typ: RelNodeType::Filter, 38 | children: vec![left.into(), right.into(), cond.into()], 39 | } 40 | } 41 | 42 | pub fn eq_pred(left: impl Into>, right: impl Into>) -> RelNode { 43 | RelNode { 44 | typ: RelNodeType::Eq, 45 | children: vec![left.into(), right.into()], 46 | } 47 | } 48 | 49 | pub fn column_ref_pred(idx: usize) -> RelNode { 50 | RelNode { 51 | typ: RelNodeType::ColumnRef(idx), 52 | children: vec![], 53 | } 54 | } 55 | 56 | pub fn const_pred(value: i64) -> RelNode { 57 | RelNode { 58 | typ: RelNodeType::Const(value), 59 | children: vec![], 60 | } 61 | } 62 | 63 | pub struct Scan(Arc); 64 | 65 | impl Scan { 66 | pub fn try_from_relnode(node: Arc) -> Option { 67 | let RelNodeType::Scan(_) = node.typ else { 68 | return None; 69 | }; 70 | Some(Self(node)) 71 | } 72 | 73 | pub fn into_relnode(self) -> Arc { 74 | self.0 75 | } 76 | 77 | pub fn table(&self) -> TableId { 78 | match &self.0.typ { 79 | RelNodeType::Scan(table) => table.clone(), 80 | _ => panic!("not a scan node"), 81 | } 82 | } 83 | } 84 | 85 | pub struct Filter(Arc); 86 | 87 | impl Filter { 88 | pub fn try_from_relnode(node: Arc) -> Option { 89 | let RelNodeType::Filter = node.typ else { 90 | return None; 91 | }; 92 | Some(Self(node)) 93 | } 94 | 95 | pub fn into_relnode(self) -> Arc { 96 | self.0 97 | } 98 | 99 | pub fn child(&self) -> Arc { 100 | self.0.children[0].clone() 101 | } 102 | 103 | pub fn cond(&self) -> Arc { 104 | self.0.children[1].clone() 105 | } 106 | } 107 | 108 | pub struct Join(Arc); 109 | 110 | impl Join { 111 | pub fn try_from_relnode(node: Arc) -> Option { 112 | let RelNodeType::Join = node.typ else { 113 | return None; 114 | }; 115 | Some(Self(node)) 116 | } 117 | 118 | pub fn into_relnode(self) -> Arc { 119 | self.0 120 | } 121 | 122 | pub fn left(&self) -> Arc { 123 | self.0.children[0].clone() 124 | } 125 | 126 | pub fn right(&self) -> Arc { 127 | self.0.children[1].clone() 128 | } 129 | 130 | pub fn cond(&self) -> Arc { 131 | self.0.children[2].clone() 132 | } 133 | } 134 | 135 | pub struct Eq(Arc); 136 | 137 | impl Eq { 138 | pub fn try_from_relnode(node: Arc) -> Option { 139 | let RelNodeType::Eq = node.typ else { 140 | return None; 141 | }; 142 | Some(Self(node)) 143 | } 144 | 145 | pub fn into_relnode(self) -> Arc { 146 | self.0 147 | } 148 | 149 | pub fn left(&self) -> Arc { 150 | self.0.children[0].clone() 151 | } 152 | 153 | pub fn right(&self) -> Arc { 154 | self.0.children[1].clone() 155 | } 156 | } 157 | 158 | pub struct ColumnRef(Arc); 159 | 160 | impl ColumnRef { 161 | pub fn try_from_relnode(node: Arc) -> Option { 162 | let RelNodeType::ColumnRef(_) = node.typ else { 163 | return None; 164 | }; 165 | Some(Self(node)) 166 | } 167 | 168 | pub fn idx(&self) -> usize { 169 | match self.0.typ { 170 | RelNodeType::ColumnRef(idx) => idx, 171 | _ => panic!("not a column ref node"), 172 | } 173 | } 174 | 175 | pub fn into_relnode(self) -> Arc { 176 | self.0 177 | } 178 | } 179 | 180 | pub struct Const(Arc); 181 | 182 | impl Const { 183 | pub fn try_from_relnode(node: Arc) -> Option { 184 | let RelNodeType::Const(_) = node.typ else { 185 | return None; 186 | }; 187 | Some(Self(node)) 188 | } 189 | 190 | pub fn value(&self) -> i64 { 191 | match self.0.typ { 192 | RelNodeType::Const(value) => value, 193 | _ => panic!("not a const node"), 194 | } 195 | } 196 | 197 | pub fn into_relnode(self) -> Arc { 198 | self.0 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /src/ir3.rs: -------------------------------------------------------------------------------- 1 | mod rel_node; 2 | 3 | pub use rel_node::*; 4 | -------------------------------------------------------------------------------- /src/ir3/rel_node.rs: -------------------------------------------------------------------------------- 1 | use std::{marker::PhantomData, sync::Arc}; 2 | 3 | #[derive(Clone)] 4 | pub struct TableId(pub usize); 5 | 6 | pub struct Scan { 7 | pub table: TableId, 8 | pub _marker: PhantomData, 9 | } 10 | 11 | impl Scan { 12 | pub fn children(&self) -> [&T; 0] { 13 | [] 14 | } 15 | 16 | pub fn children_mut(&mut self) -> [&mut T; 0] { 17 | [] 18 | } 19 | 20 | pub fn new(table: TableId) -> Self { 21 | Self { 22 | table, 23 | _marker: PhantomData, 24 | } 25 | } 26 | } 27 | 28 | pub struct Join { 29 | pub children: [T; 3], 30 | } 31 | 32 | impl Join { 33 | pub fn children(&self) -> &[T; 3] { 34 | &self.children 35 | } 36 | 37 | pub fn children_mut(&mut self) -> &mut [T; 3] { 38 | &mut self.children 39 | } 40 | 41 | pub fn new(left: T, right: T, cond: T) -> Self { 42 | Self { 43 | children: [left, right, cond], 44 | } 45 | } 46 | 47 | pub fn left(&self) -> &T { 48 | &self.children[0] 49 | } 50 | 51 | pub fn right(&self) -> &T { 52 | &self.children[1] 53 | } 54 | 55 | pub fn cond(&self) -> &T { 56 | &self.children[2] 57 | } 58 | } 59 | 60 | pub struct Filter { 61 | pub children: [T; 2], 62 | } 63 | 64 | impl Filter { 65 | pub fn children(&self) -> &[T; 2] { 66 | &self.children 67 | } 68 | 69 | pub fn children_mut(&mut self) -> &mut [T; 2] { 70 | &mut self.children 71 | } 72 | 73 | pub fn new(child: T, predicate: T) -> Self { 74 | Self { 75 | children: [child, predicate], 76 | } 77 | } 78 | 79 | pub fn child(&self) -> &T { 80 | &self.children[0] 81 | } 82 | 83 | pub fn predicate(&self) -> &T { 84 | &self.children[1] 85 | } 86 | } 87 | 88 | pub struct EqPred { 89 | pub children: [T; 2], 90 | } 91 | 92 | impl EqPred { 93 | pub fn children(&self) -> &[T; 2] { 94 | &self.children 95 | } 96 | 97 | pub fn children_mut(&mut self) -> &mut [T; 2] { 98 | &mut self.children 99 | } 100 | 101 | pub fn new(left: T, right: T) -> Self { 102 | Self { 103 | children: [left, right], 104 | } 105 | } 106 | 107 | pub fn left(&self) -> &T { 108 | &self.children[0] 109 | } 110 | 111 | pub fn right(&self) -> &T { 112 | &self.children[1] 113 | } 114 | } 115 | 116 | pub struct ColumnRefPred { 117 | pub column: usize, 118 | pub children: [T; 0], 119 | } 120 | 121 | impl ColumnRefPred { 122 | pub fn children(&self) -> &[T; 0] { 123 | &self.children 124 | } 125 | 126 | pub fn children_mut(&mut self) -> &mut [T; 0] { 127 | &mut self.children 128 | } 129 | 130 | pub fn new(column: usize) -> Self { 131 | Self { 132 | column, 133 | children: [], 134 | } 135 | } 136 | 137 | pub fn column(&self) -> usize { 138 | self.column 139 | } 140 | } 141 | 142 | pub struct ConstPred { 143 | pub value: i64, 144 | pub children: [T; 0], 145 | } 146 | 147 | impl ConstPred { 148 | pub fn children(&self) -> &[T; 0] { 149 | &self.children 150 | } 151 | 152 | pub fn children_mut(&mut self) -> &mut [T; 0] { 153 | &mut self.children 154 | } 155 | 156 | pub fn new(value: i64) -> Self { 157 | Self { 158 | value, 159 | children: [], 160 | } 161 | } 162 | 163 | pub fn value(&self) -> i64 { 164 | self.value 165 | } 166 | } 167 | 168 | enum RelNodeInner { 169 | Scan(Scan), 170 | Join(Join), 171 | Filter(Filter), 172 | Eq(EqPred), 173 | ColumnRef(ColumnRefPred), 174 | Const(ConstPred), 175 | } 176 | 177 | pub struct GroupId(usize); 178 | 179 | pub struct RelMemoNode(RelNodeInner); 180 | 181 | pub struct RelNode(RelNodeInner>); 182 | 183 | pub enum RelBindingNode { 184 | Node(RelNodeInner>), 185 | Group(GroupId), 186 | } 187 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ir2; 2 | pub mod ir3; 3 | --------------------------------------------------------------------------------