/// The binder resolves all expressions referring to schema objects such as /// tables or views with their column names and types. pubstructBinder { egraph: egg::EGraph<Node, TypeSchemaAnalysis>, catalog: Arc<RootCatalog>, contexts: Vec<Context>, /// The number of occurrences of each table in the query. table_occurrences: HashMap<TableRefId, u32>, }
/// The context of binder execution. #[derive(Debug, Default)] structContext { /// Table names that can be accessed from the current query. table_aliases: HashSet<String>, /// Column names that can be accessed from the current query. /// column_name -> (table_name -> id) aliases: HashMap<String, HashMap<String, Id>>, /// Column names that can be accessed from the outside query. /// column_name -> id output_aliases: HashMap<String, Id>, }
pub(super) fnbind_create_table(&mutself, name: ObjectName, columns: &[ColumnDef], constraints: &[TableConstraint], ) -> Result { let name = lower_case_name(&name); let (schema_name, table_name) = split_name(&name)?; let schema = self.catalog.get_schema_by_name(schema_name) .ok_or_else(|| BindError::InvalidSchema(schema_name.into()))?; if schema.get_table_by_name(table_name).is_some() { // 检查 table 是否已经存在 returnErr(BindError::TableExists(table_name.into())); }
// check duplicated column names 检查是否有重复列 letmut set = HashSet::new(); for col in columns.iter() { if !set.insert(col.name.value.to_lowercase()) { returnErr(BindError::ColumnExists(col.name.value.to_lowercase())); } }
letmut ordered_pk_ids = Binder::ordered_pks_from_columns(columns); let has_pk_from_column = !ordered_pk_ids.is_empty();
if ordered_pk_ids.len() > 1 { // 不能单独有多个主键 // multi primary key should be declared by "primary key(c1, c2...)" syntax returnErr(BindError::NotSupportedTSQL); }
let pks_name_from_constraints = Binder::pks_name_from_constraints(constraints); if has_pk_from_column && !pks_name_from_constraints.is_empty() { // can't get primary key both from "primary key(c1, c2...)" syntax and column's option returnErr(BindError::NotSupportedTSQL); } elseif !has_pk_from_column { // 主键是 primary key(c1, c2...) 这样的格式 for name in &pks_name_from_constraints { if !set.contains(name) { // 检查表中是否包含这些列 returnErr(BindError::InvalidColumn(name.clone())); } } // We have used `pks_name_from_constraints` to get the primary keys' name sorted by // declaration order in "primary key(c1, c2..)" syntax. Now we transfer the name to id // to get the sorted ID 将主键拆开,得到所有的列 ordered_pk_ids = pks_name_from_constraints .iter().map(|name| { columns.iter() .position(|c| c.name.value.eq_ignore_ascii_case(name)) .unwrap() as ColumnId }).collect(); }
letmut columns: Vec<ColumnCatalog> = columns // 生成 `ColumnCatalog` .iter().enumerate().map(|(idx, col)| { letmut col = ColumnCatalog::from(col); col.set_id(idx as ColumnId); col }).collect();
for &index in &ordered_pk_ids { // 设置 Column 主键标识 columns[index asusize].set_primary(true); columns[index asusize].set_nullable(false); }
fnbind_select(&mutself, select: Select, order_by: Vec<OrderByExpr>) -> Result { let from = self.bind_from(select.from)?; let projection = self.bind_projection(select.projection, from)?; let where_ = self.bind_where(select.selection)?; let groupby = match select.group_by { // 设置 GROUP BY group_by if group_by.is_empty() => None, group_by => Some(self.bind_groupby(group_by)?), }; let having = self.bind_having(select.having)?; let orderby = self.bind_orderby(order_by)?; let distinct = match select.distinct { None => self.egraph.add(Node::List([].into())), Some(Distinct::Distinct) => projection, Some(Distinct::On(exprs)) => self.bind_exprs(exprs)?, };
letmut plan = self.egraph.add(Node::Filter([where_, from])); letmut to_rewrite = [projection, distinct, having, orderby]; // 抽取聚合操作,生成聚合节点 plan = self.plan_agg(&mut to_rewrite, groupby, plan)?; let [mut projection, distinct, having, orderby] = to_rewrite; plan = self.egraph.add(Node::Filter([having, plan])); plan = self.plan_window(projection, distinct, orderby, plan)?; plan = self.plan_distinct(distinct, orderby, &mut projection, plan)?; plan = self.egraph.add(Node::Order([orderby, plan])); plan = self.egraph.add(Node::Proj([projection, plan])); Ok(plan) }
bind_from 会校验表是否存在(bind_table_def),并将 FROM 后面的表作为 Join 节点加入到 AST 中。如果表有别名,会将别名记录下来(也会校验是否有重复的表别名),同时也会记录表中 Column name 到别名的映射
/// Binds the VALUES clause. Returns a [`Values`](Node::Values) plan. fnbind_values(&mutself, values: Values) -> Result { let values = values.rows; letmut bound_values = Vec::with_capacity(values.len()); if values.is_empty() { returnOk(self.egraph.add(Node::Values([].into()))); }
let column_len = values[0].len(); for row in values { if row.len() != column_len { returnErr(BindError::InvalidExpression( "VALUES lists must all be the same length".into(), )); } bound_values.push(self.bind_exprs(row)?); } let id = self.egraph.add(Node::Values(bound_values.into())); self.type_(id)?; Ok(id) }