func (b *planBuilder) buildTableScanPlan(tn *ast.TableName, conditions []ast.ExprNode) Plan { p := &TableScan{ Table: tn.TableInfo, } p.SetFields(tn.GetResultFields()) var pkName model.CIStr if p.Table.PKIsHandle { for _, colInfo := range p.Table.Columns { if mysql.HasPriKeyFlag(colInfo.Flag) { pkName = colInfo.Name } } } for _, con := range conditions { if pkName.L != "" { checker := conditionChecker{tableName: tn.TableInfo.Name, pkName: pkName} if checker.check(con) { p.AccessConditions = append(p.AccessConditions, con) } else { p.FilterConditions = append(p.FilterConditions, con) } } else { p.FilterConditions = append(p.FilterConditions, con) } } return p }
func (b *executorBuilder) columnNameToPBExpr(client kv.Client, column *ast.ColumnNameExpr, tn *ast.TableName) *tipb.Expr { if !client.SupportRequestType(kv.ReqTypeSelect, int64(tipb.ExprType_ColumnRef)) { return nil } // Zero Column ID is not a column from table, can not support for now. if column.Refer.Column.ID == 0 { return nil } switch column.Refer.Expr.GetType().Tp { case mysql.TypeBit, mysql.TypeSet, mysql.TypeEnum, mysql.TypeDecimal, mysql.TypeGeometry, mysql.TypeDate, mysql.TypeNewDate, mysql.TypeDatetime, mysql.TypeTimestamp, mysql.TypeYear: return nil } matched := false for _, f := range tn.GetResultFields() { if f.TableName == column.Refer.TableName && f.Column.ID == column.Refer.Column.ID { matched = true break } } if matched { pbExpr := new(tipb.Expr) pbExpr.Tp = tipb.ExprType_ColumnRef.Enum() pbExpr.Val = codec.EncodeInt(nil, column.Refer.Column.ID) return pbExpr } // If the column ID isn't in fields, it means the column is from an outer table, // its value is available to use. return b.datumToPBExpr(client, *column.Refer.Expr.GetDatum()) }
func (b *planBuilder) buildDataSource(tn *ast.TableName) LogicalPlan { statisticTable := b.getTableStats(tn.TableInfo) if b.err != nil { return nil } p := &DataSource{ table: tn, Table: tn.TableInfo, baseLogicalPlan: newBaseLogicalPlan(Ts, b.allocator), statisticTable: statisticTable, } p.initID() // Equal condition contains a column from previous joined table. rfs := tn.GetResultFields() schema := make([]*expression.Column, 0, len(rfs)) for i, rf := range rfs { p.DBName = &rf.DBName p.Columns = append(p.Columns, rf.Column) schema = append(schema, &expression.Column{ FromID: p.id, ColName: rf.Column.Name, TblName: rf.Table.Name, DBName: rf.DBName, RetType: &rf.Column.FieldType, Position: i}) } p.SetSchema(schema) return p }
func (b *planBuilder) buildIndexScanPlan(index *model.IndexInfo, tn *ast.TableName, conditions []ast.ExprNode) Plan { ip := &IndexScan{Table: tn.TableInfo, Index: index} ip.SetFields(tn.GetResultFields()) condMap := map[ast.ExprNode]bool{} for _, con := range conditions { condMap[con] = true } out: // Build equal access conditions first. // Starts from the first index column, if equal condition is found, add it to access conditions, // proceed to the next index column. until we can't find any equal condition for the column. for ip.AccessEqualCount < len(index.Columns) { for con := range condMap { binop, ok := con.(*ast.BinaryOperationExpr) if !ok || binop.Op != opcode.EQ { continue } if ast.IsPreEvaluable(binop.L) { binop.L, binop.R = binop.R, binop.L } if !ast.IsPreEvaluable(binop.R) { continue } cn, ok2 := binop.L.(*ast.ColumnNameExpr) if !ok2 || cn.Refer.Column.Name.L != index.Columns[ip.AccessEqualCount].Name.L { continue } ip.AccessConditions = append(ip.AccessConditions, con) delete(condMap, con) ip.AccessEqualCount++ continue out } break } for con := range condMap { if ip.AccessEqualCount < len(ip.Index.Columns) { // Try to add non-equal access condition for index column at AccessEqualCount. checker := conditionChecker{tableName: tn.TableInfo.Name, idx: index, columnOffset: ip.AccessEqualCount} if checker.check(con) { ip.AccessConditions = append(ip.AccessConditions, con) } else { ip.FilterConditions = append(ip.FilterConditions, con) } } else { ip.FilterConditions = append(ip.FilterConditions, con) } } return ip }
func (b *planBuilder) buildIndexScanPlan(index *model.IndexInfo, tn *ast.TableName, conditions []ast.ExprNode) Plan { ip := &IndexScan{Table: tn.TableInfo, Index: index} ip.SetFields(tn.GetResultFields()) // Only use first column as access condition for cost estimation, // In executor, we can try to use second index column to build index range. checker := conditionChecker{tableName: tn.TableInfo.Name, idx: index, columnOffset: 0} for _, con := range conditions { if checker.check(con) { ip.AccessConditions = append(ip.AccessConditions, con) } else { ip.FilterConditions = append(ip.FilterConditions, con) } } return ip }
func (b *planBuilder) buildNewTableScanPlan(tn *ast.TableName) LogicalPlan { p := &NewTableScan{Table: tn.TableInfo, baseLogicalPlan: newBaseLogicalPlan(Ts, b.allocator)} p.initID() // Equal condition contains a column from previous joined table. rfs := tn.GetResultFields() schema := make([]*expression.Column, 0, len(rfs)) for i, rf := range rfs { p.DBName = &rf.DBName p.Columns = append(p.Columns, rf.Column) schema = append(schema, &expression.Column{ FromID: p.id, ColName: rf.Column.Name, TblName: rf.Table.Name, DBName: rf.DBName, RetType: &rf.Column.FieldType, Position: i}) } p.SetSchema(schema) return p }
func (b *planBuilder) buildNewTableScanPlan(tn *ast.TableName) Plan { p := &NewTableScan{ Table: tn.TableInfo, } p.id = b.allocID(p) // Equal condition contains a column from previous joined table. p.RefAccess = false rfs := tn.GetResultFields() schema := make([]*expression.Column, 0, len(rfs)) for _, rf := range rfs { p.DBName = &rf.DBName p.Columns = append(p.Columns, rf.Column) schema = append(schema, &expression.Column{ FromID: p.id, ColName: rf.Column.Name, TblName: rf.Table.Name, DBName: rf.DBName, RetType: &rf.Column.FieldType}) } p.SetSchema(schema) return p }