// Copyright 2015 The ql Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ql import ( "bytes" "fmt" "strings" "github.com/cznic/b" "github.com/cznic/strutil" ) const ( _ = iota indexEq // [L] indexFalse // [false] indexGe // [L, ...) indexGt // (L, ...) indexIsNotNull // (NULL, ...) indexIsNull // [NULL] indexIntervalCC // [L, H] indexIntervalCO // [L, H) indexIntervalOC // (L, H] indexIntervalOO // (L, H) indexLe // (..., H] indexLt // (..., H) indexNe // (L) indexTrue // [true] ) // Note: All plans must have a pointer receiver. Enables planA == planB operation. var ( _ plan = (*crossJoinDefaultPlan)(nil) _ plan = (*distinctDefaultPlan)(nil) _ plan = (*explainDefaultPlan)(nil) _ plan = (*filterDefaultPlan)(nil) _ plan = (*fullJoinDefaultPlan)(nil) _ plan = (*groupByDefaultPlan)(nil) _ plan = (*indexPlan)(nil) _ plan = (*leftJoinDefaultPlan)(nil) _ plan = (*limitDefaultPlan)(nil) _ plan = (*nullPlan)(nil) _ plan = (*offsetDefaultPlan)(nil) _ plan = (*orderByDefaultPlan)(nil) _ plan = (*rightJoinDefaultPlan)(nil) _ plan = (*selectFieldsDefaultPlan)(nil) _ plan = (*selectFieldsGroupPlan)(nil) _ plan = (*selectIndexDefaultPlan)(nil) _ plan = (*sysColumnDefaultPlan)(nil) _ plan = (*sysIndexDefaultPlan)(nil) _ plan = (*sysTableDefaultPlan)(nil) _ plan = (*tableDefaultPlan)(nil) _ plan = (*tableNilPlan)(nil) ) type plan interface { do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) error explain(w strutil.Formatter) fieldNames() []string filter(expr expression) (p plan, indicesSought []string, err error) hasID() bool } func isTableOrIndex(p plan) bool { switch p.(type) { case *indexPlan, *sysColumnDefaultPlan, *sysIndexDefaultPlan, *sysTableDefaultPlan, *tableDefaultPlan: return true default: return false } } // Invariants // - All interval plans produce rows in ascending index value collating order. // - L <= H type indexPlan struct { src *table cname string xname string x btreeIndex kind int // See interval* consts. lval interface{} // L, H: Ordered and comparable (lldb perspective). hval interface{} } func (r *indexPlan) doGe(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ... // --- --- --- --- --- + + +++ +++ +++ t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } for { _, h, err := it.Next() if err != nil { return noEOF(err) } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doGt(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ... // --- --- --- --- --- - - +++ +++ +++ t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } var ok bool for { k, h, err := it.Next() if err != nil { return noEOF(err) } if !ok { val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.lval) == 0 { continue } ok = true } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doInterval00(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- --- --- --- - - +++ +++ +++ +++ +++ - - --- --- --- t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } var ok bool for { k, h, err := it.Next() if err != nil { return noEOF(err) } if !ok { val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.lval) == 0 { continue } ok = true } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) == 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doIntervalOC(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- --- --- --- - - +++ +++ +++ +++ +++ + + --- --- --- t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } var ok bool for { k, h, err := it.Next() if err != nil { return noEOF(err) } if !ok { val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.lval) == 0 { continue } ok = true } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) > 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doIntervalCC(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- --- --- --- + + +++ +++ +++ +++ +++ + + --- --- --- t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) > 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doIntervalCO(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- --- --- --- + + +++ +++ +++ +++ +++ - - --- --- --- t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) >= 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doLe(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- +++ +++ +++ + + --- --- t := r.src it, err := r.x.SeekFirst() if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } if k == nil || k[0] == nil { continue } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) > 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doLt(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., H-1, H-1, H, H, H+1, H+1, ... // --- --- +++ +++ +++ - - --- --- t := r.src it, err := r.x.SeekFirst() if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } if k == nil || k[0] == nil { continue } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) >= 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doEq(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ... // --- --- --- --- --- + + --- --- --- t := r.src it, _, err := r.x.Seek([]interface{}{r.lval}) if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.lval) != 0 { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doNe(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ..., L-1, L-1, L, L, L+1, L+1, ... // --- --- +++ +++ +++ - - +++ +++ +++ t := r.src it, err := r.x.SeekFirst() if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } if k == nil || k[0] == nil { continue } val, err := expand1(k[0], nil) if err != nil { return err } if collate1(val, r.hval) == 0 { continue } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doIsNull(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ... // +++ +++ --- t := r.src it, err := r.x.SeekFirst() if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } if k != nil && k[0] != nil { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doIsNotNull(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { // nil, nil, ... // --- --- +++ t := r.src it, _, err := r.x.Seek([]interface{}{false}) // lldb collates false right after NULL. if err != nil { return noEOF(err) } for { _, h, err := it.Next() if err != nil { return noEOF(err) } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doFalse(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { t := r.src it, _, err := r.x.Seek([]interface{}{false}) if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } b, ok := k[0].(bool) if !ok || b { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) doTrue(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { t := r.src it, _, err := r.x.Seek([]interface{}{true}) if err != nil { return noEOF(err) } for { k, h, err := it.Next() if err != nil { return noEOF(err) } if _, ok := k[0].(bool); !ok { return nil } id, data, err := t.row(ctx, h) if err != nil { return err } if more, err := f(id, data); err != nil || !more { return err } } } func (r *indexPlan) do(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) error { switch r.kind { case indexEq: return r.doEq(ctx, f) case indexGe: return r.doGe(ctx, f) case indexGt: return r.doGt(ctx, f) case indexLe: return r.doLe(ctx, f) case indexLt: return r.doLt(ctx, f) case indexNe: return r.doNe(ctx, f) case indexIsNull: return r.doIsNull(ctx, f) case indexIsNotNull: return r.doIsNotNull(ctx, f) case indexFalse: return r.doFalse(ctx, f) case indexTrue: return r.doTrue(ctx, f) case indexIntervalOO: return r.doInterval00(ctx, f) case indexIntervalCC: return r.doIntervalCC(ctx, f) case indexIntervalOC: return r.doIntervalOC(ctx, f) case indexIntervalCO: return r.doIntervalCO(ctx, f) default: //dbg("", r.kind) panic("internal error 072") } } func (r *indexPlan) explain(w strutil.Formatter) { s := "" if r.kind == indexFalse { s = "!" } w.Format("┌Iterate all rows of table %q using index %q where %s%s", r.src.name, r.xname, s, r.cname) switch r.kind { case indexEq: w.Format(" == %v", value{r.lval}) case indexGe: w.Format(" >= %v", value{r.lval}) case indexGt: w.Format(" > %v", value{r.lval}) case indexLe: w.Format(" <= %v", value{r.hval}) case indexLt: w.Format(" < %v", value{r.hval}) case indexNe: w.Format(" != %v", value{r.lval}) case indexIsNull: w.Format(" IS NULL") case indexIsNotNull: w.Format(" IS NOT NULL") case indexFalse, indexTrue: // nop case indexIntervalOO: w.Format(" > %v && %s < %v", value{r.lval}, r.cname, value{r.hval}) case indexIntervalCC: w.Format(" >= %v && %s <= %v", value{r.lval}, r.cname, value{r.hval}) case indexIntervalCO: w.Format(" >= %v && %s < %v", value{r.lval}, r.cname, value{r.hval}) case indexIntervalOC: w.Format(" > %v && %s <= %v", value{r.lval}, r.cname, value{r.hval}) default: //dbg("", r.kind) panic("internal error 073") } w.Format("\n└Output field names %v\n", qnames(r.fieldNames())) } func (r *indexPlan) fieldNames() []string { return r.src.fieldNames() } func (r *indexPlan) filterEq(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(r.lval, val) == 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: if collate1(r.lval, val) >= 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '>': if collate1(r.lval, val) > 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case le: if collate1(r.lval, val) <= 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '<': if collate1(r.lval, val) < 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case neq: if collate1(r.lval, val) != 0 { return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil } return nil, nil, nil } func (r *indexPlan) filterGe(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(r.lval, val) <= 0 { r.lval = val r.kind = indexEq return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: if collate1(r.lval, val) < 0 { r.lval = val } return r, nil, nil case '>': if collate1(r.lval, val) <= 0 { r.lval = val r.kind = indexGt } return r, nil, nil case le: switch c := collate1(r.lval, val); { case c < 0: r.hval = val r.kind = indexIntervalCC return r, nil, nil case c == 0: r.kind = indexEq return r, nil, nil default: // c > 0 return &nullPlan{r.fieldNames()}, nil, nil } case '<': if collate1(r.lval, val) < 0 { r.hval = val r.kind = indexIntervalCO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case neq: switch c := collate1(r.lval, val); { case c < 0: //MAYBE ORed intervals case c == 0: r.kind = indexGt return r, nil, nil default: // c > 0 return r, nil, nil } } return nil, nil, nil } func (r *indexPlan) filterGt(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(r.lval, val) < 0 { r.lval = val r.kind = indexEq return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: if collate1(r.lval, val) < 0 { r.lval = val r.kind = indexGe } return r, nil, nil case '>': if collate1(r.lval, val) < 0 { r.lval = val } return r, nil, nil case le: if collate1(r.lval, val) < 0 { r.hval = val r.kind = indexIntervalOC return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '<': if collate1(r.lval, val) < 0 { r.hval = val r.kind = indexIntervalOO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case neq: if collate1(r.lval, val) >= 0 { return r, nil, nil } } return nil, nil, nil } func (r *indexPlan) filterLe(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(r.hval, val) >= 0 { r.lval = val r.kind = indexEq return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: switch c := collate1(r.hval, val); { case c < 0: return &nullPlan{r.fieldNames()}, nil, nil case c == 0: r.lval = val r.kind = indexEq return r, nil, nil default: // c > 0 r.lval = val r.kind = indexIntervalCC return r, nil, nil } case '>': if collate1(r.hval, val) > 0 { r.lval = val r.kind = indexIntervalOC return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case le: if collate1(r.hval, val) > 0 { r.hval = val } return r, nil, nil case '<': if collate1(r.hval, val) >= 0 { r.hval = val r.kind = indexLt } return r, nil, nil case neq: switch c := collate1(r.hval, val); { case c < 0: return r, nil, nil case c == 0: r.kind = indexLt return r, nil, nil default: // c > 0 //bop } } return nil, nil, nil } func (r *indexPlan) filterLt(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(r.hval, val) > 0 { r.lval = val r.kind = indexEq return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: if collate1(r.hval, val) > 0 { r.lval = val r.kind = indexIntervalCO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '>': if collate1(r.hval, val) > 0 { r.lval = val r.kind = indexIntervalOO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case le: if collate1(r.hval, val) > 0 { r.hval = val r.kind = indexLe } return r, nil, nil case '<': if collate1(r.hval, val) > 0 { r.hval = val } return r, nil, nil case neq: if collate1(r.hval, val) > 0 { return nil, nil, nil } return r, nil, nil } return nil, nil, nil } func (r *indexPlan) filterCC(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(val, r.lval) < 0 || collate1(val, r.hval) > 0 { return &nullPlan{r.fieldNames()}, nil, nil } r.lval = val r.kind = indexEq return r, nil, nil case ge: if collate1(val, r.lval) <= 0 { return r, nil, nil } switch c := collate1(val, r.hval); { case c < 0: r.lval = val return r, nil, nil case c == 0: r.lval = val r.kind = indexEq return r, nil, nil default: return &nullPlan{r.fieldNames()}, nil, nil } case '>': switch c := collate1(val, r.lval); { case c < 0: return r, nil, nil case c == 0: r.kind = indexIntervalOC return r, nil, nil default: if collate1(val, r.hval) < 0 { r.lval = val r.kind = indexIntervalOC return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil } case le: switch c := collate1(val, r.lval); { case c < 0: return &nullPlan{r.fieldNames()}, nil, nil case c == 0: r.kind = indexEq return r, nil, nil default: if collate1(val, r.hval) < 0 { r.hval = val } return r, nil, nil } case '<': if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } if collate1(val, r.hval) <= 0 { r.hval = val r.kind = indexIntervalCO } return r, nil, nil case neq: switch c := collate1(val, r.lval); { case c < 0: return r, nil, nil case c == 0: r.kind = indexIntervalOC return r, nil, nil default: switch c := collate1(val, r.hval); { case c == 0: r.kind = indexIntervalCO return r, nil, nil case c > 0: return r, nil, nil default: return nil, nil, nil } } } return nil, nil, nil } func (r *indexPlan) filterOC(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(val, r.lval) <= 0 || collate1(val, r.hval) > 0 { return &nullPlan{r.fieldNames()}, nil, nil } r.lval = val r.kind = indexEq return r, nil, nil case ge: if collate1(val, r.lval) <= 0 { return r, nil, nil } switch c := collate1(val, r.hval); { case c < 0: r.lval = val r.kind = indexIntervalCC return r, nil, nil case c == 0: r.lval = val r.kind = indexEq return r, nil, nil default: return &nullPlan{r.fieldNames()}, nil, nil } case '>': if collate1(val, r.lval) <= 0 { return r, nil, nil } if collate1(val, r.hval) < 0 { r.lval = val return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case le: if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } if collate1(val, r.hval) < 0 { r.hval = val } return r, nil, nil case '<': if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } switch c := collate1(val, r.hval); { case c < 0: r.hval = val r.kind = indexIntervalOO case c == 0: r.kind = indexIntervalOO } return r, nil, nil case neq: if collate1(val, r.lval) <= 0 { return r, nil, nil } switch c := collate1(val, r.hval); { case c < 0: return nil, nil, nil case c == 0: r.kind = indexIntervalOO return r, nil, nil default: return r, nil, nil } } return nil, nil, nil } func (r *indexPlan) filterOO(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(val, r.lval) <= 0 || collate1(val, r.hval) >= 0 { return &nullPlan{r.fieldNames()}, nil, nil } r.lval = val r.kind = indexEq return r, nil, nil case ge: if collate1(val, r.lval) <= 0 { return r, nil, nil } if collate1(val, r.hval) < 0 { r.lval = val r.kind = indexIntervalCO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '>': if collate1(val, r.lval) <= 0 { return r, nil, nil } if collate1(val, r.hval) < 0 { r.lval = val return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case le: if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } if collate1(val, r.hval) < 0 { r.hval = val r.kind = indexIntervalOC } return r, nil, nil case '<': if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } if collate1(val, r.hval) < 0 { r.hval = val } return r, nil, nil case neq: if collate1(val, r.lval) <= 0 || collate1(val, r.hval) >= 0 { return r, nil, nil } return nil, nil, nil } return nil, nil, nil } func (r *indexPlan) filterCO(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(val, r.lval) < 0 || collate1(val, r.hval) >= 0 { return &nullPlan{r.fieldNames()}, nil, nil } r.lval = val r.kind = indexEq return r, nil, nil case ge: if collate1(val, r.lval) <= 0 { return r, nil, nil } if collate1(val, r.hval) < 0 { r.lval = val return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case '>': switch c := collate1(val, r.lval); { case c < 0: return r, nil, nil case c == 0: r.kind = indexIntervalOO return r, nil, nil default: if collate1(val, r.hval) < 0 { r.lval = val r.kind = indexIntervalOO return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil } case le: switch c := collate1(val, r.lval); { case c < 0: return &nullPlan{r.fieldNames()}, nil, nil case c == 0: r.kind = indexEq return r, nil, nil default: if collate1(val, r.hval) < 0 { r.hval = val r.kind = indexIntervalCC } return r, nil, nil } case '<': if collate1(val, r.lval) <= 0 { return &nullPlan{r.fieldNames()}, nil, nil } if collate1(val, r.hval) < 0 { r.hval = val } return r, nil, nil case neq: switch c := collate1(val, r.lval); { case c < 0: return r, nil, nil case c == 0: r.kind = indexIntervalOO return r, nil, nil default: if collate1(val, r.hval) < 0 { return nil, nil, nil } return r, nil, nil } } return nil, nil, nil } func (r *indexPlan) filterNe(binOp2 int, val interface{}) (plan, []string, error) { switch binOp2 { case eq: if collate1(val, r.lval) != 0 { r.lval = val r.kind = indexEq return r, nil, nil } return &nullPlan{r.fieldNames()}, nil, nil case ge: switch c := collate1(val, r.lval); { case c < 0: return nil, nil, nil //TODO case c == 0: r.kind = indexGt return r, nil, nil default: r.lval = val r.kind = indexGe return r, nil, nil } case '>': if collate1(val, r.lval) < 0 { return nil, nil, nil //TODO } r.lval = val r.kind = indexGt return r, nil, nil case le: switch c := collate1(val, r.lval); { case c < 0: r.hval = val r.kind = indexLe return r, nil, nil case c == 0: r.kind = indexLt return r, nil, nil default: return nil, nil, nil //TODO } case '<': if collate1(val, r.lval) <= 0 { r.hval = val r.kind = indexLt return r, nil, nil } return nil, nil, nil //TODO case neq: if collate1(val, r.lval) == 0 { return r, nil, nil } return nil, nil, nil } return nil, nil, nil } func (r *indexPlan) filter(expr expression) (plan, []string, error) { switch x := expr.(type) { case *binaryOperation: ok, cname, val, err := x.isIdentRelOpVal() if err != nil { return nil, nil, err } if !ok || r.cname != cname { break } if val, err = typeCheck1(val, findCol(r.src.cols, cname)); err != nil { return nil, nil, err } switch r.kind { case indexEq: // [L] return r.filterEq(x.op, val) case indexGe: // [L, ...) return r.filterGe(x.op, val) case indexGt: // (L, ...) return r.filterGt(x.op, val) case indexIntervalCC: // [L, H] return r.filterCC(x.op, val) case indexIntervalCO: // [L, H) return r.filterCO(x.op, val) case indexIntervalOC: // (L, H] return r.filterOC(x.op, val) case indexIntervalOO: // (L, H) return r.filterOO(x.op, val) case indexLe: // (..., H] return r.filterLe(x.op, val) case indexLt: // (..., H) return r.filterLt(x.op, val) case indexNe: // (L) return r.filterNe(x.op, val) } case *ident: cname := x.s if r.cname != cname { break } switch r.kind { case indexFalse: // [false] return &nullPlan{r.fieldNames()}, nil, nil case indexTrue: // [true] return r, nil, nil } case *unaryOperation: if x.op != '!' { break } operand, ok := x.v.(*ident) if !ok { break } cname := operand.s if r.cname != cname { break } switch r.kind { case indexFalse: // [false] return r, nil, nil case indexTrue: // [true] return &nullPlan{r.fieldNames()}, nil, nil } } return nil, nil, nil } func (r *indexPlan) hasID() bool { return true } type explainDefaultPlan struct { s stmt } func (r *explainDefaultPlan) hasID() bool { return false } func (r *explainDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) error { var buf bytes.Buffer switch x := r.s.(type) { default: w := strutil.IndentFormatter(&buf, "│ ") x.explain(ctx, w) } a := bytes.Split(buf.Bytes(), []byte{'\n'}) for _, v := range a[:len(a)-1] { if more, err := f(nil, []interface{}{string(v)}); !more || err != nil { return err } } return nil } func (r *explainDefaultPlan) explain(w strutil.Formatter) { return } func (r *explainDefaultPlan) fieldNames() []string { return []string{""} } func (r *explainDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } type filterDefaultPlan struct { plan expr expression is []string } func (r *filterDefaultPlan) hasID() bool { return r.plan.hasID() } func (r *filterDefaultPlan) explain(w strutil.Formatter) { r.plan.explain(w) w.Format("┌Filter on %v\n", r.expr) if len(r.is) != 0 { w.Format("│Possibly useful indices\n") m := map[string]bool{} for _, v := range r.is { if !m[v] { m[v] = true n := "" for _, r := range v { if r >= '0' && r <= '9' || r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r == '_' { n += string(r) continue } n += "_" } for strings.Contains(n, "__") { n = strings.Replace(n, "__", "_", -1) } for strings.HasSuffix(n, "_") { n = n[:len(n)-1] } w.Format("│CREATE INDEX x%s ON %s;\n", n, v) } } } w.Format("└Output field names %v\n", qnames(r.plan.fieldNames())) } func (r *filterDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { m := map[interface{}]interface{}{} fields := r.plan.fieldNames() return r.plan.do(ctx, func(rid interface{}, data []interface{}) (bool, error) { for i, v := range fields { m[v] = data[i] } m["$id"] = rid val, err := r.expr.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } x, ok := val.(bool) if !ok { return false, fmt.Errorf("invalid boolean expression %s (value of type %T)", val, val) } if !x { return true, nil } return f(rid, data) }) } type crossJoinDefaultPlan struct { rsets []plan names []string fields []string } func (r *crossJoinDefaultPlan) hasID() bool { return false } func (r *crossJoinDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Compute Cartesian product of%i\n") for i, v := range r.rsets { sel := !isTableOrIndex(v) if sel { w.Format("┌Iterate all rows of virtual table %q%i\n", r.names[i]) } v.explain(w) if sel { w.Format("%u└Output field names %v\n", qnames(v.fieldNames())) } } w.Format("%u└Output field names %v\n", qnames(r.fields)) } func (r *crossJoinDefaultPlan) filter(expr expression) (plan, []string, error) { var is []string for i, v := range r.names { e2, err := expr.clone(nil, v) if err != nil { return nil, nil, err } p2, is2, err := r.rsets[i].filter(e2) is = append(is, is2...) if err != nil { return nil, nil, err } if p2 != nil { r.rsets[i] = p2 return r, is, nil } } return nil, is, nil } func (r *crossJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { if len(r.rsets) == 1 { return r.rsets[0].do(ctx, f) } ids := map[string]interface{}{} var g func([]interface{}, []plan, int) error g = func(prefix []interface{}, rsets []plan, x int) (err error) { return rsets[0].do(ctx, func(id interface{}, in []interface{}) (bool, error) { ids[r.names[x]] = id if len(rsets) > 1 { return true, g(append(prefix, in...), rsets[1:], x+1) } return f(ids, append(prefix, in...)) }) } return g(nil, r.rsets, 0) } func (r *crossJoinDefaultPlan) fieldNames() []string { return r.fields } type distinctDefaultPlan struct { src plan fields []string } func (r *distinctDefaultPlan) hasID() bool { return false } func (r *distinctDefaultPlan) explain(w strutil.Formatter) { r.src.explain(w) w.Format("┌Compute distinct rows\n└Output field names %v\n", r.fields) } func (r *distinctDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *distinctDefaultPlan) fieldNames() []string { return r.fields } func (r *distinctDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { t, err := ctx.db.store.CreateTemp(true) if err != nil { return } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() if err = r.src.do(ctx, func(id interface{}, in []interface{}) (bool, error) { if err = t.Set(in, nil); err != nil { return false, err } return true, nil }); err != nil { return } var data []interface{} more := true it, err := t.SeekFirst() for more && err == nil { data, _, err = it.Next() if err != nil { break } more, err = f(nil, data) } return noEOF(err) } type groupByDefaultPlan struct { colNames []string src plan fields []string } func (r *groupByDefaultPlan) hasID() bool { return false } func (r *groupByDefaultPlan) explain(w strutil.Formatter) { r.src.explain(w) switch { case len(r.colNames) == 0: //TODO this case should not exist for this plan, should become tableDefaultPlan w.Format("┌Group by distinct rows") default: w.Format("┌Group by") for _, v := range r.colNames { w.Format(" %s,", v) } } w.Format("\n└Output field names %v\n", qnames(r.fields)) } func (r *groupByDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *groupByDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { t, err := ctx.db.store.CreateTemp(true) if err != nil { return } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() var gcols []*col var cols []*col m := map[string]int{} for i, v := range r.src.fieldNames() { m[v] = i } for _, c := range r.colNames { i, ok := m[c] if !ok { return fmt.Errorf("unknown field %s", c) } gcols = append(gcols, &col{name: c, index: i}) } k := make([]interface{}, len(r.colNames)) //TODO optimize when len(r.cols) == 0, should become tableDefaultPlan if err = r.src.do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { infer(in, &cols) for i, c := range gcols { k[i] = in[c.index] } h0, err := t.Get(k) if err != nil { return false, err } var h int64 if len(h0) != 0 { h, _ = h0[0].(int64) } nh, err := t.Create(append([]interface{}{h, nil}, in...)...) if err != nil { return false, err } for i, c := range gcols { k[i] = in[c.index] } err = t.Set(k, []interface{}{nh}) if err != nil { return false, err } return true, nil }); err != nil { return } for i, v := range r.src.fieldNames()[:len(cols)] { cols[i].name = v cols[i].index = i } if more, err := f(nil, []interface{}{t, cols}); !more || err != nil { return err } it, err := t.SeekFirst() more := true var data []interface{} for more && err == nil { if _, data, err = it.Next(); err != nil { break } more, err = f(nil, data) } return noEOF(err) } func (r *groupByDefaultPlan) fieldNames() []string { return r.fields } type selectIndexDefaultPlan struct { nm string x interface{} } func (r *selectIndexDefaultPlan) hasID() bool { return false } func (r *selectIndexDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all values of index %q\n└Output field names N/A\n", r.nm) } func (r *selectIndexDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *selectIndexDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { var x btreeIndex switch ix := r.x.(type) { case *indexedCol: x = ix.x case *index2: x = ix.x default: panic("internal error 007") } en, err := x.SeekFirst() if err != nil { return noEOF(err) } var id int64 for { k, _, err := en.Next() if err != nil { return noEOF(err) } id++ if more, err := f(id, k); !more || err != nil { return err } } } func (r *selectIndexDefaultPlan) fieldNames() []string { return []string{r.nm} } type limitDefaultPlan struct { expr expression src plan fields []string } func (r *limitDefaultPlan) hasID() bool { return r.src.hasID() } func (r *limitDefaultPlan) explain(w strutil.Formatter) { r.src.explain(w) w.Format("┌Pass first %v records\n└Output field names %v\n", r.expr, r.fields) } func (r *limitDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *limitDefaultPlan) fieldNames() []string { return r.fields } func (r *limitDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { m := map[interface{}]interface{}{} var eval bool var lim uint64 return r.src.do(ctx, func(rid interface{}, in []interface{}) (more bool, err error) { if !eval { for i, fld := range r.fields { if fld != "" { m[fld] = in[i] } } m["$id"] = rid val, err := r.expr.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } if lim, err = limOffExpr(val); err != nil { return false, err } eval = true } switch lim { case 0: return false, nil default: lim-- return f(rid, in) } }) } type offsetDefaultPlan struct { expr expression src plan fields []string } func (r *offsetDefaultPlan) hasID() bool { return r.src.hasID() } func (r *offsetDefaultPlan) explain(w strutil.Formatter) { r.src.explain(w) w.Format("┌Skip first %v records\n└Output field names %v\n", r.expr, qnames(r.fields)) } func (r *offsetDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *offsetDefaultPlan) fieldNames() []string { return r.fields } func (r *offsetDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { m := map[interface{}]interface{}{} var eval bool var off uint64 return r.src.do(ctx, func(rid interface{}, in []interface{}) (bool, error) { if !eval { for i, fld := range r.fields { if fld != "" { m[fld] = in[i] } } m["$id"] = rid val, err := r.expr.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } if off, err = limOffExpr(val); err != nil { return false, err } eval = true } if off > 0 { off-- return true, nil } return f(rid, in) }) } type orderByDefaultPlan struct { asc bool by []expression src plan fields []string } func (r *orderByDefaultPlan) hasID() bool { return r.src.hasID() } func (r *orderByDefaultPlan) explain(w strutil.Formatter) { r.src.explain(w) w.Format("┌Order%s by", map[bool]string{false: " descending"}[r.asc]) for _, v := range r.by { w.Format(" %s,", v) } w.Format("\n└Output field names %v\n", qnames(r.fields)) } func (r *orderByDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *orderByDefaultPlan) fieldNames() []string { return r.fields } func (r *orderByDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { t, err := ctx.db.store.CreateTemp(r.asc) if err != nil { return } defer func() { if derr := t.Drop(); derr != nil && err == nil { err = derr } }() m := map[interface{}]interface{}{} flds := r.fields k := make([]interface{}, len(r.by)+1) id := int64(-1) if err = r.src.do(ctx, func(rid interface{}, in []interface{}) (bool, error) { id++ for i, fld := range flds { if fld != "" { m[fld] = in[i] } } m["$id"] = rid for i, expr := range r.by { val, err := expr.eval(ctx, m) if err != nil { return false, err } if val != nil { val, ordered, err := isOrderedType(val) if err != nil { return false, err } if !ordered { return false, fmt.Errorf("cannot order by %v (type %T)", val, val) } } k[i] = val } k[len(r.by)] = id if err = t.Set(k, in); err != nil { return false, err } return true, nil }); err != nil { return } it, err := t.SeekFirst() if err != nil { return noEOF(err) } var data []interface{} more := true for more && err == nil { if _, data, err = it.Next(); err != nil { break } more, err = f(nil, data) } return noEOF(err) } type selectFieldsDefaultPlan struct { flds []*fld src plan fields []string } func (r *selectFieldsDefaultPlan) hasID() bool { return r.src.hasID() } func (r *selectFieldsDefaultPlan) explain(w strutil.Formatter) { //TODO check for non existing fields r.src.explain(w) w.Format("┌Evaluate") for _, v := range r.flds { w.Format(" %s as %s,", v.expr, fmt.Sprintf("%q", v.name)) } w.Format("\n└Output field names %v\n", qnames(r.fields)) } func (r *selectFieldsDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *selectFieldsDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { fields := r.src.fieldNames() m := map[interface{}]interface{}{} return r.src.do(ctx, func(rid interface{}, in []interface{}) (bool, error) { for i, nm := range fields { if nm != "" { m[nm] = in[i] } } m["$id"] = rid out := make([]interface{}, len(r.flds)) for i, fld := range r.flds { var err error if out[i], err = fld.expr.eval(ctx, m); err != nil { return false, err } } return f(rid, out) }) } func (r *selectFieldsDefaultPlan) fieldNames() []string { return r.fields } type selectFieldsGroupPlan struct { flds []*fld src *groupByDefaultPlan fields []string } func (r *selectFieldsGroupPlan) hasID() bool { return false } func (r *selectFieldsGroupPlan) explain(w strutil.Formatter) { //TODO check for non existing fields r.src.explain(w) w.Format("┌Evaluate") for _, v := range r.flds { w.Format(" %s as %s,", v.expr, fmt.Sprintf("%q", v.name)) } w.Format("\n└Output field names %v\n", qnames(r.fields)) } func (r *selectFieldsGroupPlan) fieldNames() []string { return r.fields } func (r *selectFieldsGroupPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *selectFieldsGroupPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { var t temp var cols []*col var err error out := make([]interface{}, len(r.flds)) ok := false rows := false if err = r.src.do(ctx, func(rid interface{}, in []interface{}) (bool, error) { if ok { h := in[0].(int64) m := map[interface{}]interface{}{} for h != 0 { in, err = t.Read(nil, h, cols...) if err != nil { return false, err } rec := in[2:] for i, c := range cols { if nm := c.name; nm != "" { m[nm] = rec[i] } } m["$id"] = rid for _, fld := range r.flds { if _, err = fld.expr.eval(ctx, m); err != nil { return false, err } } h = in[0].(int64) } m["$agg"] = true for i, fld := range r.flds { if out[i], err = fld.expr.eval(ctx, m); err != nil { return false, err } } rows = true return f(nil, out) } ok = true t = in[0].(temp) cols = in[1].([]*col) if len(r.flds) == 0 { // SELECT * r.flds = make([]*fld, len(cols)) for i, v := range cols { r.flds[i] = &fld{expr: &ident{v.name}, name: v.name} } out = make([]interface{}, len(r.flds)) } return true, nil }); err != nil { return err } if rows { return nil } m := map[interface{}]interface{}{"$agg0": true} // aggregate empty record set for i, fld := range r.flds { if out[i], err = fld.expr.eval(ctx, m); err != nil { return err } } _, err = f(nil, out) return err } type sysColumnDefaultPlan struct{} func (r *sysColumnDefaultPlan) hasID() bool { return false } func (r *sysColumnDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all rows of table \"__Column\"\n└Output field names %v\n", qnames(r.fieldNames())) } func (r *sysColumnDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *sysColumnDefaultPlan) fieldNames() []string { return []string{"TableName", "Ordinal", "Name", "Type"} } func (r *sysColumnDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { rec := make([]interface{}, 4) di, err := ctx.db.info() if err != nil { return err } var id int64 for _, ti := range di.Tables { rec[0] = ti.Name var ix int64 for _, ci := range ti.Columns { ix++ rec[1] = ix rec[2] = ci.Name rec[3] = ci.Type.String() id++ if more, err := f(id, rec); !more || err != nil { return err } } } return nil } type sysIndexDefaultPlan struct{} func (r *sysIndexDefaultPlan) hasID() bool { return false } func (r *sysIndexDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all rows of table \"__Index\"\n└Output field names %v\n", qnames(r.fieldNames())) } func (r *sysIndexDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *sysIndexDefaultPlan) fieldNames() []string { return []string{"TableName", "ColumnName", "Name", "IsUnique"} } func (r *sysIndexDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { rec := make([]interface{}, 4) di, err := ctx.db.info() if err != nil { return err } var id int64 for _, xi := range di.Indices { rec[0] = xi.Table rec[1] = xi.Column rec[2] = xi.Name rec[3] = xi.Unique id++ if more, err := f(id, rec); !more || err != nil { return err } } return nil } type sysTableDefaultPlan struct{} func (r *sysTableDefaultPlan) hasID() bool { return false } func (r *sysTableDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all rows of table \"__Table\"\n└Output field names %v\n", qnames(r.fieldNames())) } func (r *sysTableDefaultPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *sysTableDefaultPlan) fieldNames() []string { return []string{"Name", "Schema"} } func (r *sysTableDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) error { rec := make([]interface{}, 2) di, err := ctx.db.info() if err != nil { return err } var id int64 for _, ti := range di.Tables { rec[0] = ti.Name a := []string{} for _, ci := range ti.Columns { s := "" if ci.NotNull { s += " NOT NULL" } if c := ci.Constraint; c != "" { s += " " + c } if d := ci.Default; d != "" { s += " DEFAULT " + d } a = append(a, fmt.Sprintf("%s %s%s", ci.Name, ci.Type, s)) } rec[1] = fmt.Sprintf("CREATE TABLE %s (%s);", ti.Name, strings.Join(a, ", ")) id++ if more, err := f(id, rec); !more || err != nil { return err } } return nil } type tableNilPlan struct { t *table } func (r *tableNilPlan) hasID() bool { return true } func (r *tableNilPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all rows of table %q\n└Output field names %v\n", r.t.name, qnames(r.fieldNames())) } func (r *tableNilPlan) fieldNames() []string { return []string{} } func (r *tableNilPlan) filter(expr expression) (plan, []string, error) { return nil, nil, nil } func (r *tableNilPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (bool, error)) (err error) { t := r.t h := t.head cols := t.cols for h > 0 { rec, err := t.store.Read(nil, h, cols...) // 0:next, 1:id, 2...: data if err != nil { return err } if m, err := f(rec[1], nil); !m || err != nil { return err } h = rec[0].(int64) // next } return nil } type tableDefaultPlan struct { t *table fields []string } func (r *tableDefaultPlan) hasID() bool { return true } func (r *tableDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Iterate all rows of table %q\n└Output field names %v\n", r.t.name, qnames(r.fields)) } func (r *tableDefaultPlan) filterBinOp(x *binaryOperation) (plan, []string, error) { ok, cn, rval, err := x.isIdentRelOpVal() if err != nil { return nil, nil, err } if !ok { return nil, nil, nil } t := r.t c, ix := t.findIndexByColName(cn) if ix == nil { // Column cn has no index. return nil, []string{fmt.Sprintf("%s(%s)", t.name, cn)}, nil } if rval, err = typeCheck1(rval, c); err != nil { return nil, nil, err } switch x.op { case eq: return &indexPlan{t, cn, ix.name, ix.x, indexEq, rval, rval}, nil, nil case '<': return &indexPlan{t, cn, ix.name, ix.x, indexLt, nil, rval}, nil, nil case le: return &indexPlan{t, cn, ix.name, ix.x, indexLe, nil, rval}, nil, nil case ge: return &indexPlan{t, cn, ix.name, ix.x, indexGe, rval, nil}, nil, nil case '>': return &indexPlan{t, cn, ix.name, ix.x, indexGt, rval, nil}, nil, nil case neq: return &indexPlan{t, cn, ix.name, ix.x, indexNe, rval, rval}, nil, nil default: panic("internal error 069") } } func (r *tableDefaultPlan) filterIdent(x *ident, trueValue bool) (plan, []string, error) { cn := x.s t := r.t for _, v := range t.cols { if v.name != cn { continue } if v.typ != qBool { return nil, nil, nil } xi := v.index + 1 // 0: id() if xi >= len(t.indices) { return nil, nil, nil } ix := t.indices[xi] if ix == nil { // Column cn has no index. return nil, []string{fmt.Sprintf("%s(%s)", t.name, cn)}, nil } kind := indexFalse if trueValue { kind = indexTrue } return &indexPlan{t, cn, ix.name, ix.x, kind, nil, nil}, nil, nil } return nil, nil, nil } func (r *tableDefaultPlan) filterIsNull(x *isNull) (plan, []string, error) { ok, cn := isColumnExpression(x.expr) if !ok { return nil, nil, nil } t := r.t _, ix := t.findIndexByColName(cn) if ix == nil { // Column cn has no index. return nil, []string{fmt.Sprintf("%s(%s)", t.name, cn)}, nil } switch { case x.not: return &indexPlan{t, cn, ix.name, ix.x, indexIsNotNull, nil, nil}, nil, nil default: return &indexPlan{t, cn, ix.name, ix.x, indexIsNull, nil, nil}, nil, nil } } func (r *tableDefaultPlan) filter(expr expression) (plan, []string, error) { cols := mentionedColumns(expr) for _, v := range r.fields { delete(cols, v) } for k := range cols { return nil, nil, fmt.Errorf("unknown field %s", k) } var is []string //TODO var sexpr string //TODO for _, ix := range t.indices2 { //TODO if len(ix.exprList) != 1 { //TODO continue //TODO } //TODO if sexpr == "" { //TODO sexpr = expr.String() //TODO } //TODO if ix.sources[0] != sexpr { //TODO continue //TODO } //TODO } switch x := expr.(type) { case *binaryOperation: return r.filterBinOp(x) case *ident: return r.filterIdent(x, true) case *isNull: return r.filterIsNull(x) case *unaryOperation: if x.op != '!' { break } if operand, ok := x.v.(*ident); ok { return r.filterIdent(operand, false) } default: //dbg("", expr) return nil, is, nil //TODO } return nil, is, nil } func (r *tableDefaultPlan) do(ctx *execCtx, f func(interface{}, []interface{}) (bool, error)) (err error) { t := r.t cols := t.cols h := t.head for h > 0 { rec, err := t.row0(ctx, h) if err != nil { return err } h = rec[0].(int64) id := rec[1].(int64) for i, c := range cols { rec[i] = rec[c.index+2] } if m, err := f(id, rec[:len(cols)]); !m || err != nil { return err } } return nil } func (r *tableDefaultPlan) fieldNames() []string { return r.fields } type nullPlan struct { fields []string } func (r *nullPlan) hasID() bool { return false } func (r *nullPlan) fieldNames() []string { return r.fields } func (r *nullPlan) explain(w strutil.Formatter) { w.Format("┌Iterate no rows\n└Output field names %v\n", qnames(r.fields)) } func (r *nullPlan) do(*execCtx, func(interface{}, []interface{}) (bool, error)) error { return nil } func (r *nullPlan) filter(expr expression) (plan, []string, error) { return r, nil, nil } type leftJoinDefaultPlan struct { on expression rsets []plan names []string right int fields []string } func (r *leftJoinDefaultPlan) hasID() bool { return false } func (r *leftJoinDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Compute Cartesian product of%i\n") for i, v := range r.rsets { sel := !isTableOrIndex(v) if sel { w.Format("┌Iterate all rows of virtual table %q%i\n", r.names[i]) } v.explain(w) if sel { w.Format("%u└Output field names %v\n", qnames(v.fieldNames())) } } w.Format("Extend the product with all NULL rows of %q when no match for %v%u\n", r.names[len(r.names)-1], r.on) w.Format("└Output field names %v\n", qnames(r.fields)) } func (r *leftJoinDefaultPlan) filter(expr expression) (plan, []string, error) { var is []string for i, v := range r.names { e2, err := expr.clone(nil, v) if err != nil { return nil, nil, err } p2, is2, err := r.rsets[i].filter(e2) is = append(is, is2...) if err != nil { return nil, nil, err } if p2 != nil { r.rsets[i] = p2 return r, is, nil } } return nil, is, nil } type rightJoinDefaultPlan struct { leftJoinDefaultPlan } func (r *rightJoinDefaultPlan) hasID() bool { return false } func (r *rightJoinDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Compute Cartesian product of%i\n") for i, v := range r.rsets { sel := !isTableOrIndex(v) if sel { w.Format("┌Iterate all rows of virtual table %q%i\n", r.names[i]) } v.explain(w) if sel { w.Format("%u└Output field names %v\n", qnames(v.fieldNames())) } } w.Format("Extend the product with all NULL rows of all but %q when no match for %v%u\n", r.names[len(r.names)-1], r.on) w.Format("└Output field names %v\n", qnames(r.fields)) } func (r *rightJoinDefaultPlan) filter(expr expression) (plan, []string, error) { var is []string for i, v := range r.names { e2, err := expr.clone(nil, v) if err != nil { return nil, nil, err } p2, is2, err := r.rsets[i].filter(e2) is = append(is, is2...) if err != nil { return nil, nil, err } if p2 != nil { r.rsets[i] = p2 return r, is, nil } } return nil, is, nil } type fullJoinDefaultPlan struct { leftJoinDefaultPlan } func (r *fullJoinDefaultPlan) hasID() bool { return false } func (r *fullJoinDefaultPlan) explain(w strutil.Formatter) { w.Format("┌Compute Cartesian product of%i\n") for i, v := range r.rsets { sel := !isTableOrIndex(v) if sel { w.Format("┌Iterate all rows of virtual table %q%i\n", r.names[i]) } v.explain(w) if sel { w.Format("%u└Output field names %v\n", qnames(v.fieldNames())) } } w.Format("Extend the product with all NULL rows of %q when no match for %v\n", r.names[len(r.names)-1], r.on) w.Format("Extend the product with all NULL rows of all but %q when no match for %v%u\n", r.names[len(r.names)-1], r.on) w.Format("└Output field names %v\n", qnames(r.fields)) } func (r *fullJoinDefaultPlan) filter(expr expression) (plan, []string, error) { var is []string for i, v := range r.names { e2, err := expr.clone(nil, v) if err != nil { return nil, nil, err } p2, is2, err := r.rsets[i].filter(e2) is = append(is, is2...) if err != nil { return nil, nil, err } if p2 != nil { r.rsets[i] = p2 return r, is, nil } } return nil, is, nil } func (r *leftJoinDefaultPlan) fieldNames() []string { return r.fields } func (r *leftJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) error { m := map[interface{}]interface{}{} ids := map[string]interface{}{} var g func([]interface{}, []plan, int) error var match bool g = func(prefix []interface{}, rsets []plan, x int) (err error) { return rsets[0].do(ctx, func(id interface{}, in []interface{}) (bool, error) { ids[r.names[x]] = id row := append(prefix, in...) if len(rsets) > 1 { if len(rsets) == 2 { match = false } if err = g(row, rsets[1:], x+1); err != nil { return false, err } if len(rsets) != 2 || match { return true, nil } ids[r.names[x+1]] = nil return f(ids, append(row, make([]interface{}, r.right)...)) } for i, fld := range r.fields { if fld != "" { m[fld] = row[i] } } val, err := r.on.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } x, ok := val.(bool) if !ok { return false, fmt.Errorf("invalid ON expression %s (value of type %T)", val, val) } if !x { return true, nil } match = true return f(ids, row) }) } return g(nil, r.rsets, 0) } func (r *rightJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) error { right := r.right left := len(r.fields) - right n := len(r.rsets) m := map[interface{}]interface{}{} ids := map[string]interface{}{} var g func([]interface{}, []plan, int) error var match bool nf := len(r.fields) fields := append(append([]string(nil), r.fields[nf-right:]...), r.fields[:nf-right]...) g = func(prefix []interface{}, rsets []plan, x int) (err error) { return rsets[0].do(ctx, func(id interface{}, in []interface{}) (bool, error) { ids[r.names[x]] = id row := append(prefix, in...) if len(rsets) > 1 { if len(rsets) == n { match = false } if err = g(row, rsets[1:], x+1); err != nil { return false, err } if len(rsets) != n || match { return true, nil } for i := 0; i < n-1; i++ { ids[r.names[i]] = nil } // rigth, left -> left, right return f(ids, append(make([]interface{}, left), row[:right]...)) } for i, fld := range fields { if fld != "" { m[fld] = row[i] } } val, err := r.on.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } x, ok := val.(bool) if !ok { return false, fmt.Errorf("invalid ON expression %s (value of type %T)", val, val) } if !x { return true, nil } match = true // rigth, left -> left, right return f(ids, append(append([]interface{}(nil), row[right:]...), row[:right]...)) }) } return g(nil, append([]plan{r.rsets[n-1]}, r.rsets[:n-1]...), 0) } func (r *fullJoinDefaultPlan) do(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) error { b3 := b.TreeNew(func(a, b interface{}) int { x := a.(int64) y := b.(int64) if x < y { return -1 } if x == y { return 0 } return 1 }) m := map[interface{}]interface{}{} ids := map[string]interface{}{} var g func([]interface{}, []plan, int) error var match bool var rid int64 firstR := true g = func(prefix []interface{}, rsets []plan, x int) (err error) { return rsets[0].do(ctx, func(id interface{}, in []interface{}) (bool, error) { ids[r.names[x]] = id row := append(prefix, in...) if len(rsets) > 1 { if len(rsets) == 2 { match = false rid = 0 } if err = g(row, rsets[1:], x+1); err != nil { return false, err } if len(rsets) == 2 { firstR = false } if len(rsets) != 2 || match { return true, nil } ids[r.names[x+1]] = nil return f(ids, append(row, make([]interface{}, r.right)...)) } rid++ if firstR { b3.Set(rid, in) } for i, fld := range r.fields { if fld != "" { m[fld] = row[i] } } val, err := r.on.eval(ctx, m) if err != nil { return false, err } if val == nil { return true, nil } x, ok := val.(bool) if !ok { return false, fmt.Errorf("invalid ON expression %s (value of type %T)", val, val) } if !x { return true, nil } match = true b3.Delete(rid) return f(ids, row) }) } if err := g(nil, r.rsets, 0); err != nil { return err } it, err := b3.SeekFirst() if err != nil { return noEOF(err) } pref := make([]interface{}, len(r.fields)-r.right) for { _, v, err := it.Next() if err != nil { return noEOF(err) } more, err := f(nil, append(pref, v.([]interface{})...)) if err != nil || !more { return err } } }