Beispiel #1
0
func newViewPrimaryIndex(v *viewIndexer, name string) (*primaryIndex, error) {
	ddoc := newPrimaryDDoc(name)
	doc := expression.NewIdentifier(v.keyspace.Name())
	meta := expression.NewMeta(doc)
	mdid := expression.NewField(meta, expression.NewFieldName("id"))

	inst := primaryIndex{
		viewIndex{
			name:     name,
			using:    datastore.VIEW,
			on:       datastore.IndexKey{mdid},
			ddoc:     ddoc,
			keyspace: v.keyspace,
			view:     v,
		},
	}

	err := inst.putDesignDoc()
	if err != nil {
		return nil, err
	}

	err = inst.WaitForIndex()
	if err != nil {
		return nil, err
	}

	return &inst, nil
}
Beispiel #2
0
func loadViewIndexes(v *viewIndexer) ([]*datastore.Index, error) {

	b := v.keyspace
	rows, err := b.cbbucket.GetDDocs()
	if err != nil {
		return nil, err
	}

	inames := make([]string, 0, len(rows.Rows))
	nonUsableIndexes := make([]string, 0)

	for _, row := range rows.Rows {
		cdoc := row.DDoc
		id := cdoc.Meta["id"].(string)
		if strings.HasPrefix(id, "_design/ddl_") {
			iname := strings.TrimPrefix(id, "_design/ddl_")
			inames = append(inames, iname)
		} else if strings.HasPrefix(id, "_design/dev_") {
			// append this to the list of non-usuable indexes
			iname := strings.TrimPrefix(id, "_design/dev_")
			for _, name := range v.nonUsableIndexes {
				if iname == name {
					continue
				}
			}
			nonUsableIndexes = append(nonUsableIndexes, iname)

		} else if strings.HasPrefix(id, "_design/") {
			iname := strings.TrimPrefix(id, "_design/")
			for _, name := range v.nonUsableIndexes {
				if iname == name {
					continue
				}
			}
			nonUsableIndexes = append(nonUsableIndexes, iname)
		}

	}

	indexes := make([]*datastore.Index, 0, len(inames))
	for _, iname := range inames {
		ddname := "ddl_" + iname
		jdoc, err := getDesignDoc(b, ddname)
		if err != nil {
			return nil, err
		}
		jview, ok := jdoc.Views[iname]
		if !ok {
			nonUsableIndexes = append(nonUsableIndexes, iname)
			logging.Errorf("Missing view for index %v ", iname)
			continue
		}

		exprlist := make([]expression.Expression, 0, len(jdoc.IndexOn))

		for _, ser := range jdoc.IndexOn {
			if iname == PRIMARY_INDEX {
				doc := expression.NewIdentifier(b.Name())
				meta := expression.NewMeta(doc)
				mdid := expression.NewField(meta, expression.NewFieldName("id"))
				exprlist = append(exprlist, mdid)
			} else {
				expr, err := parser.Parse(ser)
				if err != nil {
					nonUsableIndexes = append(nonUsableIndexes, iname)
					logging.Errorf("Cannot unmarshal expression for index  %v", iname)
					continue
				}
				exprlist = append(exprlist, expr)
			}
		}
		if len(exprlist) != len(jdoc.IndexOn) {
			continue
		}

		ddoc := designdoc{
			name:     ddname,
			viewname: iname,
			mapfn:    jview.Map,
			reducefn: jview.Reduce,
		}
		if ddoc.checksum() != jdoc.IndexChecksum {
			nonUsableIndexes = append(nonUsableIndexes, iname)
			logging.Errorf("Warning - checksum failed on index  %v", iname)
			continue
		}

		var index datastore.Index

		logging.Infof("Found index name %v keyspace %v", iname, b.Name())
		if iname == PRIMARY_INDEX {
			index = &viewIndex{
				name:     iname,
				keyspace: b,
				view:     v,
				using:    datastore.VIEW,
				ddoc:     &ddoc,
				on:       exprlist,
			}
			indexes = append(indexes, &index)
		} else {
			index = &viewIndex{
				name:     iname,
				keyspace: b,
				view:     v,
				using:    datastore.VIEW,
				ddoc:     &ddoc,
				on:       exprlist,
			}
			indexes = append(indexes, &index)
		}
	}
	v.nonUsableIndexes = nonUsableIndexes

	if len(indexes) == 0 {
		return nil, nil
	}

	return indexes, nil
}
Beispiel #3
0
func TestConverter(t *testing.T) {

	s1 := NewJSConverter().Visit(
		expression.NewLT(constant("a"), constant("b")))

	s2 := "(\"a\" < \"b\")"

	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(
		expression.NewBetween(constant("a"),
			constant("b"),
			constant("c")))

	s2 = "(\"a\" > \"b\" && \"a\" < \"c\")"

	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewAdd(
		expression.NewSub(constant("a"), constant("b")),
		expression.NewDiv(constant("a"), constant("b"))))

	s2 = "((\"a\" - \"b\") + (\"a\" / \"b\"))"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewLength(constant("abc")))
	s2 = "(\"abc\".length)"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewUpper(constant("abc")))
	s2 = "(\"abc\".toUpperCase())"

	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewStrToMillis(constant("Wed, 09 Aug 1995 00:00:00")))
	s2 = "(Date.parse(\"Wed, 09 Aug 1995 00:00:00\"))"

	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewContains(constant("dfgabc"), constant("abc")))
	s2 = "(\"dfgabc\".indexOf(\"abc\"))"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewSubstr(constant("dfgabc"), constant(1), constant(4)))
	s2 = "(\"dfgabc\".substring(1,4))"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewAdd(expression.NewContains(constant("dfgabc"), constant("abc")), expression.NewSubstr(constant("dfgabc"), constant(1), constant(4))))
	s2 = "((\"dfgabc\".indexOf(\"abc\")) + (\"dfgabc\".substring(1,4)))"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	doc := expression.NewIdentifier("bucket")
	m1 := expression.NewField(doc, expression.NewFieldName("id"))
	m2 := expression.NewField(doc, expression.NewFieldName("type"))

	s1 = NewJSConverter().Visit(expression.NewOr(
		expression.NewUpper(m1), expression.NewLower(m2)))

	s2 = "((`bucket`.`id`.toUpperCase()) || (`bucket`.`type`.toLowerCase()))"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	doc = expression.NewIdentifier("bucket")
	m1 = expression.NewField(doc, expression.NewFieldName("geo"))
	m2 = expression.NewField(m1, expression.NewFieldName("accuracy"))

	s1 = NewJSConverter().Visit(m2)
	s2 = "`bucket`.`geo`.`accuracy`"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	doc = expression.NewIdentifier("bucket")
	m1 = expression.NewField(doc, expression.NewElement(expression.NewFieldName("address"), constant(0)))

	s1 = NewJSConverter().Visit(m1)
	s2 = "`bucket`.`address`[0]"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

	s1 = NewJSConverter().Visit(expression.NewLength(expression.NewElement(doc, expression.NewFieldName("type"))))
	s2 = "(`bucket`[`type`].length)"
	if s1 != s2 {
		t.Errorf(" mismatch s1 %s s2 %s", s1, s2)
	}

}
Beispiel #4
0
func (this *builder) selectScan(keyspace datastore.Keyspace,
	node *algebra.KeyspaceTerm) (Operator, error) {
	if this.where == nil {
		return this.selectPrimaryScan(keyspace, node)
	}

	nnf := planner.NewNNF()
	where := this.where.Copy()
	where, err := nnf.Map(where)
	if err != nil {
		return nil, err
	}

	formalizer := expression.NewFormalizer()
	formalizer.Keyspace = node.Alias()
	primaryKey := expression.NewField(
		expression.NewMeta(expression.NewConstant(node.Alias())),
		expression.NewFieldName("id"))

	indexers, err := keyspace.Indexers()
	if err != nil {
		return nil, err
	}

	indexes := make([]datastore.Index, 0, len(indexers)*16)
	primaryIndexes := make(map[datastore.Index]bool, len(indexers)*2)

	for _, indexer := range indexers {
		idxs, err := indexer.Indexes()
		if err != nil {
			return nil, err
		}

		indexes = append(indexes, idxs...)

		primaryIdxs, err := indexer.PrimaryIndexes()
		if err != nil {
			return nil, err
		}

		for _, p := range primaryIdxs {
			primaryIndexes[p] = true
		}
	}

	unfiltered := make(map[datastore.Index]expression.Expression, len(indexes))
	filtered := make(map[datastore.Index]expression.Expression, len(indexes))

	for _, index := range indexes {
		state, _, er := index.State()
		if er != nil {
			return nil, er
		}

		if state != datastore.ONLINE {
			continue
		}

		var key expression.Expression

		if primaryIndexes[index] {
			key = primaryKey
		} else {
			rangeKey := index.RangeKey()
			if len(rangeKey) == 0 || rangeKey[0] == nil {
				// Index not rangeable
				continue
			}

			key := rangeKey[0].Copy()

			key, err = formalizer.Map(key)
			if err != nil {
				return nil, err
			}

			key, err = nnf.Map(key)
			if err != nil {
				return nil, err
			}
		}

		if !planner.SargableFor(where, key) {
			// Index not applicable
			continue
		}

		indexCond := index.Condition()
		if indexCond == nil {
			unfiltered[index] = key
			continue
		}

		indexCond = indexCond.Copy()

		indexCond, err = formalizer.Map(indexCond)
		if err != nil {
			return nil, err
		}

		indexCond, err = nnf.Map(indexCond)
		if err != nil {
			return nil, err
		}

		if planner.SubsetOf(where, indexCond) {
			// Index condition satisfies query condition
			filtered[index] = key
			break
		}
	}

	var indexMap map[datastore.Index]expression.Expression
	if len(filtered) > 0 {
		indexMap = filtered
	} else if len(unfiltered) > 0 {
		indexMap = unfiltered
	}

	for index, key := range indexMap {
		spans := planner.SargFor(where, key)
		var scan Operator
		scan = NewIndexScan(index, node, spans, false, math.MaxInt64)
		if len(spans) > 1 {
			// Use UnionScan to de-dup multiple spans
			scan = NewUnionScan(scan)
		}

		return scan, err
	}

	return this.selectPrimaryScan(keyspace, node)
}