func (r *TableDefaultPlan) filterBinOp(ctx context.Context, x *expression.BinaryOperation) (plan.Plan, bool, error) { ok, name, rval, err := x.IsIdentCompareVal() if err != nil { return r, false, errors.Trace(err) } if !ok { return r, false, nil } if rval == nil { // if nil, any <, <=, >, >=, =, != operator will do nothing // any value compared null returns null // TODO: if we support <=> later, we must handle null return &NullPlan{r.GetFields()}, true, nil } _, tn, cn := field.SplitQualifiedName(name) t := r.T if tn != "" && tn != t.TableName().L { return r, false, nil } c := column.FindCol(t.Cols(), cn) if c == nil { return nil, false, errors.Errorf("No such column: %s", cn) } var seekVal interface{} if seekVal, err = types.Convert(rval, &c.FieldType); err != nil { return nil, false, errors.Trace(err) } spans := toSpans(x.Op, rval, seekVal) if c.IsPKHandleColumn(r.T.Meta()) { if r.rangeScan { spans = filterSpans(r.spans, spans) } return &TableDefaultPlan{ T: r.T, Fields: r.Fields, rangeScan: true, spans: spans, }, true, nil } else if r.rangeScan { // Already filtered on PK handle column, should not switch to index plan. return r, false, nil } ix := t.FindIndexByColName(cn) if ix == nil { // Column cn has no index. return r, false, nil } return &indexPlan{ src: t, col: c, unique: ix.Unique, idxName: ix.Name.O, idx: ix.X, spans: spans, }, true, nil }
// Filter implements plan.Plan Filter interface. // Filter merges BinaryOperations and determines the lower and upper bound. func (r *indexPlan) Filter(ctx context.Context, expr expression.Expression) (plan.Plan, bool, error) { var spans []*indexSpan switch x := expr.(type) { case *expression.BinaryOperation: ok, name, val, err := x.IsIdentCompareVal() if err != nil { return nil, false, err } if !ok { break } _, tname, cname := field.SplitQualifiedName(name) if tname != "" && r.src.TableName().L != tname { break } if r.col.ColumnInfo.Name.L != cname { break } seekVal, err := types.Convert(val, &r.col.FieldType) if err != nil { return nil, false, errors.Trace(err) } spans = filterSpans(r.spans, toSpans(x.Op, val, seekVal)) case *expression.Ident: if r.col.Name.L != x.L { break } spans = filterSpans(r.spans, toSpans(opcode.GE, minNotNullVal, nil)) case *expression.UnaryOperation: if x.Op != '!' { break } cname, ok := x.V.(*expression.Ident) if !ok { break } if r.col.Name.L != cname.L { break } spans = filterSpans(r.spans, toSpans(opcode.EQ, nil, nil)) } if spans == nil { return r, false, nil } return &indexPlan{ src: r.src, col: r.col, unique: r.unique, idxName: r.idxName, idx: r.idx, spans: spans, }, true, nil }
func findColumnByName(t table.Table, name string) (*column.Col, error) { _, tableName, colName := field.SplitQualifiedName(name) if len(tableName) > 0 && tableName != t.TableName().O { return nil, errors.Errorf("unknown field %s.%s", tableName, colName) } c := column.FindCol(t.Cols(), colName) if c == nil { return nil, errors.Errorf("unknown field %s", colName) } return c, nil }
func (r *TableDefaultPlan) filterBinOp(ctx context.Context, x *expression.BinaryOperation) (plan.Plan, bool, error) { ok, name, rval, err := x.IsIdentCompareVal() if err != nil { return r, false, err } if !ok { return r, false, nil } if rval == nil { // if nil, any <, <=, >, >=, =, != operator will do nothing // any value compared null returns null // TODO: if we support <=> later, we must handle null return &NullPlan{r.GetFields()}, true, nil } _, tn, cn := field.SplitQualifiedName(name) t := r.T if tn != "" && tn != t.TableName().L { return r, false, nil } c := column.FindCol(t.Cols(), cn) if c == nil { return nil, false, errors.Errorf("No such column: %s", cn) } ix := t.FindIndexByColName(cn) if ix == nil { // Column cn has no index. return r, false, nil } var seekVal interface{} if seekVal, err = types.Convert(rval, &c.FieldType); err != nil { return nil, false, err } return &indexPlan{ src: t, col: c, idxName: ix.Name.O, idx: ix.X, spans: toSpans(x.Op, rval, seekVal), }, true, nil }