func TestPrettyPrint(t *testing.T) { defer leaktest.AfterTest(t) tm, _ := time.Parse(time.UnixDate, "Sat Mar 7 11:06:39 UTC 2015") testCases := []struct { key roachpb.Key exp string }{ // local {StoreIdentKey(), "/Local/Store/storeIdent"}, {StoreGossipKey(), "/Local/Store/gossipBootstrap"}, {SequenceCacheKeyPrefix(roachpb.RangeID(1000001), []byte("test0")), `/Local/RangeID/1000001/SequenceCache/"test0"`}, {SequenceCacheKey(roachpb.RangeID(1000001), []byte("test0"), uint32(111), uint32(222)), `/Local/RangeID/1000001/SequenceCache/"test0"/epoch:111/seq:222`}, {RaftLeaderLeaseKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftLeaderLease"}, {RaftTombstoneKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftTombstone"}, {RaftHardStateKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftHardState"}, {RaftAppliedIndexKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftAppliedIndex"}, {RaftLogKey(roachpb.RangeID(1000001), uint64(200001)), "/Local/RangeID/1000001/RaftLog/logIndex:200001"}, {RaftTruncatedStateKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftTruncatedState"}, {RaftLastIndexKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RaftLastIndex"}, {RangeLastVerificationTimestampKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RangeLastVerificationTimestamp"}, {RangeStatsKey(roachpb.RangeID(1000001)), "/Local/RangeID/1000001/RangeStats"}, {MakeRangeKeyPrefix(roachpb.RKey("ok")), `/Local/Range/"ok"`}, {RangeDescriptorKey(roachpb.RKey("111")), `/Local/Range/RangeDescriptor/"111"`}, {RangeTreeNodeKey(roachpb.RKey("111")), `/Local/Range/RangeTreeNode/"111"`}, {TransactionKey(roachpb.Key("111"), []byte("22222")), `/Local/Range/Transaction/addrKey:/"111"/id:"22222"`}, {LocalMax, "/Local/Max"}, // system {roachpb.MakeKey(Meta2Prefix, roachpb.Key("foo")), `/Meta2/"foo"`}, {roachpb.MakeKey(Meta1Prefix, roachpb.Key("foo")), `/Meta1/"foo"`}, {StoreStatusKey(2222), "/System/StatusStore/2222"}, {NodeStatusKey(1111), "/System/StatusNode/1111"}, {SystemMax, "/System/Max"}, // table {UserTableDataMin, "/Table/50"}, {MakeTablePrefix(111), "/Table/111"}, {MakeKey(MakeTablePrefix(42), roachpb.RKey("foo")), `/Table/42/"foo"`}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeFloat(nil, float64(233.221112)))), "/Table/42/233.221112"}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeVarint(nil, 1222)), roachpb.RKey(encoding.EncodeString(nil, "handsome man"))), `/Table/42/1222/"handsome man"`}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeBytes(nil, []byte{1, 2, 8, 255}))), `/Table/42/"\x01\x02\b\xff"`}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeBytes(nil, []byte{1, 2, 8, 255})), roachpb.RKey("bar")), `/Table/42/"\x01\x02\b\xff"/"bar"`}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeNull(nil))), "/Table/42/NULL"}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeNotNull(nil))), "/Table/42/#"}, {MakeKey(MakeTablePrefix(42), roachpb.RKey(encoding.EncodeTime(nil, tm))), "/Table/42/Sat Mar 7 11:06:39 UTC 2015"}, // others {MakeKey([]byte("")), "/Min"}, {MakeKey(MakeTablePrefix(42), roachpb.RKey([]byte{0x20, 'a', 0x00, 0x02})), "/Table/42/<util/encoding/encoding.go:407: unknown escape>"}, } for i, test := range testCases { keyInfo := PrettyPrint(test.key) if test.exp != keyInfo { t.Fatalf("%d: expected %s, got %s", i, test.exp, keyInfo) } if test.exp != test.key.String() { t.Fatalf("%d: expected %s, got %s", i, test.exp, keyInfo) } } }
// makeSpans constructs the spans for an index given a set of constraints. func makeSpans(constraints indexConstraints, tableID ID, indexID IndexID) []span { prefix := roachpb.Key(MakeIndexKeyPrefix(tableID, indexID)) spans := []span{{ start: append(roachpb.Key(nil), prefix...), end: append(roachpb.Key(nil), prefix...), }} var buf [100]byte for i, c := range constraints { // Is this the last end constraint? We perform special processing on the // last end constraint to account for the exclusive nature of the scan end // key. lastEnd := c.end != nil && (i+1 == len(constraints) || constraints[i+1].end == nil) if (c.start != nil && c.start.Operator == parser.In) || (c.end != nil && c.end.Operator == parser.In) { var e *parser.ComparisonExpr if c.start != nil && c.start.Operator == parser.In { e = c.start } else { e = c.end } // Special handling of IN exprssions. Such expressions apply to both the // start and end key, but also cause an explosion in the number of spans // searched within an index. tuple, ok := e.Right.(parser.DTuple) if !ok { break } // For each of the existing spans and for each value in the tuple, create // a new span. existingSpans := spans spans = make([]span, 0, len(existingSpans)*len(tuple)) for _, datum := range tuple { var start, end []byte switch t := datum.(type) { case parser.DTuple: start = buf[:0] for _, i := range c.tupleMap { var err error if start, err = encodeTableKey(start, t[i]); err != nil { panic(err) } } end = start if lastEnd { end = nil for i := range c.tupleMap { d := t[c.tupleMap[i]] if i+1 == len(c.tupleMap) { d = d.Next() } var err error if end, err = encodeTableKey(end, d); err != nil { panic(err) } } } default: var err error if start, err = encodeTableKey(buf[:0], datum); err != nil { panic(err) } end = start if lastEnd { var err error if end, err = encodeTableKey(nil, datum.Next()); err != nil { panic(err) } } } for _, s := range existingSpans { if c.start != nil { s.start = append(append(roachpb.Key(nil), s.start...), start...) } if c.end != nil { s.end = append(append(roachpb.Key(nil), s.end...), end...) } spans = append(spans, s) } } continue } if c.start != nil { // We have a start constraint. switch c.start.Operator { case parser.NE, parser.IsNot: // A != or IS NOT NULL expression allows us to constrain the start of // the range to not include NULL. for i := range spans { spans[i].start = encoding.EncodeNotNull(spans[i].start) } default: if datum, ok := c.start.Right.(parser.Datum); ok { key, err := encodeTableKey(buf[:0], datum) if err != nil { panic(err) } // Append the constraint to all of the existing spans. for i := range spans { spans[i].start = append(spans[i].start, key...) } } } } if c.end != nil { // We have an end constraint. switch c.end.Operator { case parser.Is: // An IS NULL expressions allows us to constrain the end of the range // to stop at NULL. for i := range spans { spans[i].end = encoding.EncodeNotNull(spans[i].end) } default: if datum, ok := c.end.Right.(parser.Datum); ok { if lastEnd && c.end.Operator != parser.LT { datum = datum.Next() } key, err := encodeTableKey(buf[:0], datum) if err != nil { panic(err) } // Append the constraint to all of the existing spans. for i := range spans { spans[i].end = append(spans[i].end, key...) } } if c.start == nil && (i == 0 || constraints[i-1].start != nil) { // This is the first constraint for which we don't have a start // constraint. Add a not-NULL endpoint. for i := range spans { spans[i].start = encoding.EncodeNotNull(spans[i].start) } } } } } if len(constraints) == 0 || constraints[0].end == nil { for i := range spans { spans[i].end = spans[i].end.PrefixEnd() } } // Remove any spans which are empty. This can happen for constraints such as // "a > 1 AND a < 2" which we do not simplify to false but which is treated // as "a >= 2 AND a < 2" for span generation. n := 0 for _, s := range spans { if bytes.Compare(s.start, s.end) < 0 { spans[n] = s n++ } } spans = spans[:n] return spans }