-
Notifications
You must be signed in to change notification settings - Fork 600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(frontend): bind project #615
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM
use crate::expr::ExprImpl; | ||
|
||
impl Binder { | ||
pub fn bind_projection(&mut self, projection: Vec<SelectItem>) -> Result<Vec<ExprImpl>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
pub fn bind_projection(&mut self, projection: Vec<SelectItem>) -> Result<Vec<ExprImpl>> { | |
pub fn bind_select_items(&mut self, projection: Vec<SelectItem>) -> Result<Vec<ExprImpl>> { |
use crate::optimizer::PlanRef; | ||
|
||
impl Planner { | ||
pub(super) fn plan_projection( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend to call it Project
instead of Projection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we create one file per operator? At least for projection we can just place it under planner/select.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was also thinking to put this directly in select
, as it just calls the constructor and is only used there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emmm I did this because bind_vec_table_with_join() is also in a file..........
and although bind_projection() is simple now, it will become complicated as we develop more features....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend to call it
Project
instead ofProjection
self.bind_projection(select.projection)
The reason why I use projection is that BoundSelect use projection(not project) as its member.........
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bind_vec_table_with_join
is in a file intended to handle all types of TableRef
s: base table, join, and subquery. It may be split into smaller files later.
although bind_projection() is simple now, it will become complicated as we develop more features
It is likely {bind,plan}_select
will become complicated, with projection / select_items being one of the steps or even several parts that are hard to be extracted into a dedicated function.
Some(column) => Ok(ExprImpl::InputRef(Box::new(InputRef::new( | ||
column.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Column id is different from column index. In the catalog, each column has its own id; while for InputRef, it cares about how to locate the column from input chunk. In the simplest form the input is from scan.
For example, if we scan start(id=2), end(id=7)
and want to evaluate end - start
, it would be Sub(InputRef(1), InputRef(0))
.
Err(ErrorCode::ItemNotFound(format!("Invalid table: {}", table_name)).into()) | ||
} | ||
}, | ||
None => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two branches are a little bit duplicated. We can start by supporting column names only as there is only one table now. When there are multiple tables, maybe we can use a reversed map column -> table -> schema
: (1) when only column name is provided and it is unambiguous after lookup, the column is successfully bound to the only table; (2) when the column lookup yields multiple tables, the extra table name can be used or it is an ambiguous reference error.
write!( | ||
f, | ||
"LogicalProject {{ exprs: {:?}, expr_alias: {:?} }}", | ||
self.exprs(), | ||
self.expr_alias(), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try this: f.debug_struct().field().field().finish()
.
9e93885
to
747b530
Compare
.or_default() | ||
.push(ColumnBinding::new( | ||
table_name.clone(), | ||
column.id() as usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, the bind_table
always returns a relation with all columns in that table, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By design, there will be an ordered list Vec<ColumnDesc>
or Vec<ColumnId>
in the table catalog to denote the ordering of columns in a table. So here you should get each column according to that and assign index from 0, instead of column.id() as usize
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may imagine ColumnId as a random number unique for each column :)
@likg227 I suggest that you can add a test in rust/frontend/tests/testdata/basic_query.yaml since I've found that this pr may not be runnable. A simple test case is: create table t (v1 int, v2 int);
select v1 from t; |
747b530
to
6566f98
Compare
Codecov Report
@@ Coverage Diff @@
## main #615 +/- ##
============================================
+ Coverage 71.34% 71.40% +0.06%
- Complexity 2701 2706 +5
============================================
Files 894 898 +4
Lines 51165 51338 +173
Branches 1724 1730 +6
============================================
+ Hits 36503 36659 +156
- Misses 13849 13864 +15
- Partials 813 815 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("LogicalProject") | ||
.field("exprs", self.exprs()) | ||
.field("expr_alias", &format_args!("{:?}", self.expr_alias())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.field("expr_alias", self.expr_alias())
not enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ignore the schema field which is useless to display and the input field which is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was asking about the field expr_alias
. It turns out the following works:
.field("expr_alias", &self.expr_alias)
.field("expr_alias", &self.expr_alias())
but not:.field("expr_alias", self.expr_alias())
because&[Option<String>]
cannot be used as&dyn Debug
.
} | ||
} | ||
|
||
pub fn bind_all_columns(&mut self) -> Result<Vec<ExprImpl>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like this has closer relationship with select
/projection
than as part of binder/expr
. What about move this when we fix the ordering of expansion?
.iter() | ||
.find(|column| column.table_name == *table_name) | ||
{ | ||
Some(column) => Ok(ExprImpl::InputRef(Box::new(InputRef::new( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: ExprImpl::InputRef(Box::new(a))
-> a.to_expl_impl()
What's changed and what's your intention?
PLEASE DO NOT LEAVE THIS EMPTY !!!
Please explain IN DETAIL what the changes are in this PR and why they are needed:
In this pr, I support queries like
explain select v1 from t;
.Please notice that I haven't support recursive BindContext, and I will support it in the future.
Checklist
Refer to a related PR or issue link (optional)