// Next implements plan.Plan Next interface. func (r *HavingPlan) Next(ctx context.Context) (row *plan.Row, err error) { if r.evalArgs == nil { r.evalArgs = map[interface{}]interface{}{} } for { var srcRow *plan.Row srcRow, err = r.Src.Next(ctx) if srcRow == nil || err != nil { return nil, errors.Trace(err) } r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { v, err0 := GetIdentValue(name, r.Src.GetFields(), srcRow.Data, field.CheckFieldFlag) if err0 == nil { return v, nil } // try to find in outer query return getIdentValueFromOuterQuery(ctx, name) } r.evalArgs[expression.ExprEvalPositionFunc] = func(position int) (interface{}, error) { // position is in [1, len(fields)], so we must decrease 1 to get correct index // TODO: check position invalidation return srcRow.Data[position-1], nil } var v bool v, err = expression.EvalBoolExpr(ctx, r.Expr, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if v { row = srcRow return } } }
func (r *JoinPlan) nextCrossJoin(ctx context.Context) (row *plan.Row, err error) { for { if r.curRow == nil { r.curRow, err = r.Left.Next(ctx) if err != nil { return nil, errors.Trace(err) } if r.curRow == nil { return nil, nil } if r.On != nil { tempExpr := r.On.Clone() visitor := NewIdentEvalVisitor(r.Left.GetFields(), r.curRow.Data) _, err = tempExpr.Accept(visitor) if err != nil { return nil, errors.Trace(err) } var filtered bool r.tempPlan, filtered, err = r.Right.Filter(ctx, tempExpr) if filtered { log.Debugf("cross join use index") } } else { r.tempPlan = r.Right } } var rightRow *plan.Row rightRow, err = r.tempPlan.Next(ctx) if err != nil { return nil, errors.Trace(err) } if rightRow == nil { r.curRow = nil r.tempPlan.Close() continue } joinedRow := append(r.curRow.Data, rightRow.Data...) if r.On != nil { r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joinedRow, field.DefaultFieldFlag) } b, err := expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if !b { // If On condition not satisified, drop this row continue } } row = &plan.Row{ Data: joinedRow, RowKeys: append(r.curRow.RowKeys, rightRow.RowKeys...), } return } }
func (r *JoinPlan) findMatchedRows(ctx context.Context, row *plan.Row, p plan.Plan, right bool) (err error) { r.cursor = 0 r.matchedRows = nil p.Close() for { var cmpRow *plan.Row cmpRow, err = p.Next(ctx) if err != nil { return errors.Trace(err) } if cmpRow == nil { break } // Do append(s1, s2) safely. Sometime the s1 capability is larger than its real length, so // multi append may overwrite last valid data, e.g, // s1 = make([]interface{}, 0, 1) // s = append(s1, []interface{}{1}) // ss = append(ss, s) // s = append(s1, []interface{}{2}) // ss = append(ss, s) // We will see that ss only contains 2. joined := make([]interface{}, 0, len(cmpRow.Data)+len(row.Data)) if right { joined = append(append(joined, cmpRow.Data...), row.Data...) } else { joined = append(append(joined, row.Data...), cmpRow.Data...) } r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joined, field.DefaultFieldFlag) } var b bool b, err = expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return errors.Trace(err) } if b { cmpRow.Data = joined keys := make([]*plan.RowKeyEntry, 0, len(row.RowKeys)+len(cmpRow.RowKeys)) cmpRow.RowKeys = append(append(keys, row.RowKeys...), cmpRow.RowKeys...) r.matchedRows = append(r.matchedRows, cmpRow) } } if len(r.matchedRows) == 0 { if right { leftLen := len(r.Fields) - len(r.Right.GetFields()) row.Data = append(make([]interface{}, leftLen), row.Data...) } else { rightLen := len(r.Fields) - len(r.Left.GetFields()) row.Data = append(row.Data, make([]interface{}, rightLen)...) } r.matchedRows = append(r.matchedRows, row) } return nil }
func (s *ShowPlan) evalCondition(ctx context.Context, m map[interface{}]interface{}) (bool, error) { var cond expression.Expression if s.Pattern != nil { cond = s.Pattern } else if s.Where != nil { cond = s.Where } if cond == nil { return true, nil } return expression.EvalBoolExpr(ctx, cond, m) }
func (r *JoinPlan) findMatchedRows(ctx context.Context, row *plan.Row, right bool) (err error) { var p plan.Plan if right { p = r.Left } else { p = r.Right } r.cursor = 0 r.matchedRows = nil p.Close() for { var cmpRow *plan.Row cmpRow, err = p.Next(ctx) if err != nil { return errors.Trace(err) } if cmpRow == nil { break } var joined []interface{} if right { joined = append(cmpRow.Data, row.Data...) } else { joined = append(row.Data, cmpRow.Data...) } r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joined, field.DefaultFieldFlag) } var b bool b, err = expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return errors.Trace(err) } if b { cmpRow.Data = joined cmpRow.RowKeys = append(row.RowKeys, cmpRow.RowKeys...) r.matchedRows = append(r.matchedRows, cmpRow) } } if len(r.matchedRows) == 0 { if right { leftLen := len(r.Fields) - len(r.Right.GetFields()) row.Data = append(make([]interface{}, leftLen), row.Data...) } else { rightLen := len(r.Fields) - len(r.Left.GetFields()) row.Data = append(row.Data, make([]interface{}, rightLen)...) } r.matchedRows = append(r.matchedRows, row) } return nil }
func (s *DeleteStmt) hitWhere(ctx context.Context, fields []*field.ResultField, data []interface{}) (bool, error) { if s.Where == nil { return true, nil } m := map[interface{}]interface{}{} m[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return plans.GetIdentValue(name, fields, data, field.DefaultFieldFlag) } ok, err := expression.EvalBoolExpr(ctx, s.Where, m) if err != nil { return false, errors.Trace(err) } return ok, nil }
func (s *DeleteStmt) hitWhere(ctx context.Context, t table.Table, data []interface{}) (bool, error) { if s.Where == nil { return true, nil } m := map[interface{}]interface{}{} // Set parameter for evaluating expression. for _, col := range t.Cols() { m[col.Name.L] = data[col.Offset] } ok, err := expression.EvalBoolExpr(ctx, s.Where, m) if err != nil { return false, errors.Trace(err) } return ok, nil }
func (r *JoinPlan) nextCrossJoin(ctx context.Context) (row *plan.Row, err error) { for { if r.curRow == nil { r.curRow, err = r.Left.Next(ctx) if err != nil { return nil, errors.Trace(err) } if r.curRow == nil { return nil, nil } } var rightRow *plan.Row rightRow, err = r.Right.Next(ctx) if err != nil { return nil, errors.Trace(err) } if rightRow == nil { r.curRow = nil r.Right.Close() continue } joinedRow := append(r.curRow.Data, rightRow.Data...) if r.On != nil { r.evalArgs[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joinedRow, field.DefaultFieldFlag) } b, err := expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if !b { // If On condition not satisified, drop this row continue } } row = &plan.Row{ Data: joinedRow, RowKeys: append(r.curRow.RowKeys, rightRow.RowKeys...), } return } }
// Next implements plan.Plan Next interface. func (r *HavingPlan) Next(ctx context.Context) (row *plan.Row, err error) { if r.evalArgs == nil { r.evalArgs = map[interface{}]interface{}{} } for { var srcRow *plan.Row srcRow, err = r.Src.Next(ctx) if srcRow == nil || err != nil { return nil, errors.Trace(err) } r.evalArgs[expression.ExprEvalIdentReferFunc] = func(name string, scope int, index int) (interface{}, error) { if scope == expression.IdentReferFromTable { return srcRow.FromData[index], nil } else if scope == expression.IdentReferSelectList { return srcRow.Data[index], nil } // try to find in outer query return getIdentValueFromOuterQuery(ctx, name) } r.evalArgs[expression.ExprEvalPositionFunc] = func(position int) (interface{}, error) { // position is in [1, len(fields)], so we must decrease 1 to get correct index // TODO: check position invalidation return srcRow.Data[position-1], nil } var v bool v, err = expression.EvalBoolExpr(ctx, r.Expr, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if v { row = srcRow return } } }
func (s *ShowPlan) fetchAll(ctx context.Context) error { // TODO split this function switch s.Target { case stmt.ShowEngines: row := &plan.Row{ Data: []interface{}{"InnoDB", "DEFAULT", "Supports transactions, row-level locking, and foreign keys", "YES", "YES", "YES"}, } s.rows = append(s.rows, row) case stmt.ShowDatabases: dbs := sessionctx.GetDomain(ctx).InfoSchema().AllSchemaNames() // TODO: let information_schema be the first database sort.Strings(dbs) for _, d := range dbs { s.rows = append(s.rows, &plan.Row{Data: []interface{}{d}}) } case stmt.ShowTables: is := sessionctx.GetDomain(ctx).InfoSchema() dbName := model.NewCIStr(s.DBName) if !is.SchemaExists(dbName) { return errors.Errorf("Can not find DB: %s", dbName) } // sort for tables var tableNames []string for _, v := range is.SchemaTables(dbName) { tableNames = append(tableNames, v.TableName().L) } sort.Strings(tableNames) for _, v := range tableNames { s.rows = append(s.rows, &plan.Row{Data: []interface{}{v}}) } case stmt.ShowColumns: is := sessionctx.GetDomain(ctx).InfoSchema() dbName := model.NewCIStr(s.DBName) if !is.SchemaExists(dbName) { return errors.Errorf("Can not find DB: %s", dbName) } tbName := model.NewCIStr(s.TableName) tb, err := is.TableByName(dbName, tbName) if err != nil { return errors.Errorf("Can not find table: %s", s.TableName) } cols := tb.Cols() for _, col := range cols { if !s.isColOK(col) { continue } desc := column.NewColDesc(col) // The FULL keyword causes the output to include the column collation and comments, // as well as the privileges you have for each column. row := &plan.Row{} if s.Full { row.Data = []interface{}{ desc.Field, desc.Type, desc.Collation, desc.Null, desc.Key, desc.DefaultValue, desc.Extra, desc.Privileges, desc.Comment, } } else { row.Data = []interface{}{ desc.Field, desc.Type, desc.Null, desc.Key, desc.DefaultValue, desc.Extra, } } s.rows = append(s.rows, row) } case stmt.ShowWarnings: // empty result case stmt.ShowCharset: // See: http://dev.mysql.com/doc/refman/5.7/en/show-character-set.html descs := charset.GetAllCharsets() for _, desc := range descs { row := &plan.Row{ Data: []interface{}{desc.Name, desc.Desc, desc.DefaultCollation, desc.Maxlen}, } s.rows = append(s.rows, row) } case stmt.ShowVariables: sessionVars := variable.GetSessionVars(ctx) for _, v := range variable.SysVars { if s.Pattern != nil { s.Pattern.Expr = expression.Value{Val: v.Name} r, err := s.Pattern.Eval(ctx, nil) if err != nil { return errors.Trace(err) } match, ok := r.(bool) if !ok { return errors.Errorf("Eval like pattern error") } if !match { continue } } else if s.Where != nil { m := map[interface{}]interface{}{} m[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { if strings.EqualFold(name, "Variable_name") { return v.Name, nil } return nil, errors.Errorf("unknown field %s", name) } match, err := expression.EvalBoolExpr(ctx, s.Where, m) if err != nil { return errors.Trace(err) } if !match { continue } } value := v.Value if !s.GlobalScope { // Try to get Session Scope variable value sv, ok := sessionVars.Systems[v.Name] if ok { value = sv } } row := &plan.Row{Data: []interface{}{v.Name, value}} s.rows = append(s.rows, row) } case stmt.ShowCollation: collations := charset.GetCollations() for _, v := range collations { if s.Pattern != nil { s.Pattern.Expr = expression.Value{Val: v.Name} r, err := s.Pattern.Eval(ctx, nil) if err != nil { return errors.Trace(err) } match, ok := r.(bool) if !ok { return errors.Errorf("Eval like pattern error") } if !match { continue } } else if s.Where != nil { m := map[interface{}]interface{}{} m[expression.ExprEvalIdentFunc] = func(name string) (interface{}, error) { switch { case strings.EqualFold(name, "Collation"): return v.Name, nil case strings.EqualFold(name, "Charset"): return v.CharsetName, nil case strings.EqualFold(name, "Id"): return v.ID, nil case strings.EqualFold(name, "Default"): if v.IsDefault { return "Yes", nil } return "", nil case strings.EqualFold(name, "Compiled"): return "Yes", nil case strings.EqualFold(name, "Sortlen"): // TODO: add sort length in Collation return 1, nil default: return nil, errors.Errorf("unknown field %s", name) } } match, err := expression.EvalBoolExpr(ctx, s.Where, m) if err != nil { return errors.Trace(err) } if !match { continue } } isDefault := "" if v.IsDefault { isDefault = "Yes" } row := &plan.Row{Data: []interface{}{v.Name, v.CharsetName, v.ID, isDefault, "Yes", 1}} s.rows = append(s.rows, row) } } return nil }
func (r *JoinPlan) nextCrossJoin(ctx context.Context) (row *plan.Row, err error) { visitor := newJoinIdentVisitor(0) for { if r.curRow == nil { r.curRow, err = r.Left.Next(ctx) if err != nil { return nil, errors.Trace(err) } if r.curRow == nil { return nil, nil } if r.On != nil { tempExpr := r.On.Clone() visitor.row = r.curRow.Data _, err = tempExpr.Accept(visitor) if err != nil { return nil, errors.Trace(err) } var filtered bool r.tempPlan, filtered, err = r.Right.Filter(ctx, tempExpr) if filtered { log.Debugf("cross join use index") } } else { r.tempPlan = r.Right } } var rightRow *plan.Row rightRow, err = r.tempPlan.Next(ctx) if err != nil { return nil, errors.Trace(err) } if rightRow == nil { r.curRow = nil r.tempPlan.Close() continue } // To prevent outer modify the slice. See comment above. joinedRow := make([]interface{}, 0, len(r.curRow.Data)+len(rightRow.Data)) joinedRow = append(append(joinedRow, r.curRow.Data...), rightRow.Data...) if r.On != nil { r.evalArgs[expression.ExprEvalIdentReferFunc] = func(name string, scope int, index int) (interface{}, error) { return joinedRow[index], nil } b, err := expression.EvalBoolExpr(ctx, r.On, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if !b { // If On condition not satisified, drop this row continue } } row = &plan.Row{ Data: joinedRow, RowKeys: append(r.curRow.RowKeys, rightRow.RowKeys...), } return } }