// Do implements plan.Plan Do interface. // It scans rows over SrcPlan and check if it meets all conditions in Expr. func (r *HavingPlan) Do(ctx context.Context, f plan.RowIterFunc) (err error) { m := map[interface{}]interface{}{} return r.Src.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.Src.GetFields(), in, field.CheckFieldFlag) } m[expressions.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 in[position-1], nil } v, err := expressions.EvalBoolExpr(ctx, r.Expr, m) if err != nil { return false, err } if !v { return true, nil } return f(rid, in) }) }
// 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[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.Src.GetFields(), srcRow.Data, field.CheckFieldFlag) } r.evalArgs[expressions.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 = expressions.EvalBoolExpr(ctx, r.Expr, r.evalArgs) if err != nil { return nil, errors.Trace(err) } if v { row = srcRow return } } }
func (r *JoinPlan) doCrossJoin(ctx context.Context, f plan.RowIterFunc) error { return r.Left.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { leftRow := appendRow(nil, in) m := map[interface{}]interface{}{} if err := r.Right.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { row := appendRow(leftRow, in) if r.On != nil { m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.Fields, row, field.DefaultFieldFlag) } b, err := expressions.EvalBoolExpr(ctx, r.On, m) if err != nil { return false, err } if !b { // If On condition not satisified, drop this row return true, nil } } return f(rid, row) }); err != nil { return false, err } return true, nil }) }
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[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joined, field.DefaultFieldFlag) } var b bool b, err = expressions.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, 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 := expressions.EvalBoolExpr(ctx, s.Where, m) if err != nil { return false, errors.Trace(err) } return ok, nil }
func (r *JoinPlan) doFullJoin(ctx context.Context, f plan.RowIterFunc) error { // we just support full join simplify, because MySQL doesn't support it // for full join, we can use two phases // 1, t1 LEFT JOIN t2 // 2, t2 anti semi LEFT JOIN t1 if err := r.doLeftJoin(ctx, f); err != nil { return err } // anti semi left join return r.Right.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { rightRow := appendRow(nil, in) matched := false m := map[interface{}]interface{}{} if err := r.Left.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { row := appendRow(in, rightRow) m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.Fields, row, field.DefaultFieldFlag) } b, err := expressions.EvalBoolExpr(ctx, r.On, m) if err != nil { return false, err } if b { // here means the condition matched, we can skip this row matched = true return false, nil } return true, nil }); err != nil { return false, err } if !matched { // Fill left with NULL leftLen := len(r.Fields) - len(r.Right.GetFields()) return f(rid, appendRow(make([]interface{}, leftLen), rightRow)) } return true, 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[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return GetIdentValue(name, r.Fields, joinedRow, field.DefaultFieldFlag) } b, err := expressions.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) doRightJoin(ctx context.Context, f plan.RowIterFunc) error { // right join is the same as left join, only reverse the row result return r.Right.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { rightRow := appendRow(nil, in) matched := false m := map[interface{}]interface{}{} if err := r.Left.Do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { row := appendRow(in, rightRow) m[expressions.ExprEvalIdentFunc] = func(name string) (interface{}, error) { return getIdentValue(name, r.Fields, row, field.DefaultFieldFlag) } b, err := expressions.EvalBoolExpr(ctx, r.On, m) if err != nil { return false, err } if !b { return true, nil } matched = true return f(rid, row) }); err != nil { return false, err } if !matched { // Fill left with NULL leftLen := len(r.Fields) - len(r.Right.GetFields()) return f(rid, appendRow(make([]interface{}, leftLen), rightRow)) } return true, nil }) }
func (s *ShowPlan) fetchAll(ctx context.Context) error { 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 { p, ok := s.Pattern.(*expressions.PatternLike) if !ok { return errors.Errorf("Like should be a PatternLike expression") } p.Expr = expressions.Value{Val: v.Name} r, err := p.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[expressions.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 := expressions.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) } } return nil }