// DecodeIndexKey decodes the values that are a part of the specified index // key. ValTypes is a slice returned from makeKeyVals. The remaining bytes in the // index key are returned which will either be an encoded column ID for the // primary key index, the primary key suffix for non-unique secondary indexes // or unique secondary indexes containing NULL or empty. If the given descriptor // does not match the key, false is returned with no error. func DecodeIndexKey( a *DatumAlloc, desc *TableDescriptor, indexID IndexID, valTypes, vals []parser.Datum, colDirs []encoding.Direction, key []byte, ) ([]byte, bool, error) { var decodedTableID ID var decodedIndexID IndexID var err error if index, err := desc.FindIndexByID(indexID); err == nil && len(index.Interleave.Ancestors) > 0 { for _, ancestor := range index.Interleave.Ancestors { key, decodedTableID, decodedIndexID, err = DecodeTableIDIndexID(key) if err != nil { return nil, false, err } if decodedTableID != ancestor.TableID || decodedIndexID != ancestor.IndexID { return nil, false, nil } length := int(ancestor.SharedPrefixLen) key, err = DecodeKeyVals(a, valTypes[:length], vals[:length], colDirs[:length], key) valTypes, vals, colDirs = valTypes[length:], vals[length:], colDirs[length:] // We reuse NotNullDescending as the interleave sentinel, consume it. var ok bool key, ok = encoding.DecodeIfNotNull(key) if !ok { return nil, false, nil } } } key, decodedTableID, decodedIndexID, err = DecodeTableIDIndexID(key) if err != nil { return nil, false, err } if decodedTableID != desc.ID || decodedIndexID != indexID { return nil, false, nil } key, err = DecodeKeyVals(a, valTypes, vals, colDirs, key) if err != nil { return nil, false, err } // We're expecting a column family id next (a varint). If descNotNull is // actually next, then this key is for a child table. if _, ok := encoding.DecodeIfNotNull(key); ok { return nil, false, nil } return key, true, nil }
func decodeKeyPrint(key roachpb.Key) string { var buf bytes.Buffer for k := 0; len(key) > 0; k++ { var err error switch encoding.PeekType(key) { case encoding.Null: key, _ = encoding.DecodeIfNull(key) fmt.Fprintf(&buf, "/NULL") case encoding.NotNull: key, _ = encoding.DecodeIfNotNull(key) fmt.Fprintf(&buf, "/#") case encoding.Int: var i int64 key, i, err = encoding.DecodeVarintAscending(key) if err == nil { fmt.Fprintf(&buf, "/%d", i) } case encoding.Float: var f float64 key, f, err = encoding.DecodeFloatAscending(key, nil) if err == nil { fmt.Fprintf(&buf, "/%f", f) } case encoding.Bytes: var s string key, s, err = encoding.DecodeStringAscending(key, nil) if err == nil { fmt.Fprintf(&buf, "/%q", s) } case encoding.BytesDesc: var s string key, s, err = encoding.DecodeStringDescending(key, nil) if err == nil { fmt.Fprintf(&buf, "/%q", s) } case encoding.Time: var t time.Time key, t, err = encoding.DecodeTimeAscending(key) if err == nil { fmt.Fprintf(&buf, "/%s", t.UTC().Format(time.UnixDate)) } case encoding.TimeDesc: var t time.Time key, t, err = encoding.DecodeTimeDescending(key) if err == nil { fmt.Fprintf(&buf, "/%s", t.UTC().Format(time.UnixDate)) } default: // This shouldn't ever happen, but if it does let the loop exit. fmt.Fprintf(&buf, "/%q", []byte(key)) key = nil } if err != nil { fmt.Fprintf(&buf, "/<%v>", err) continue } } return buf.String() }
// DecodeIndexKeyPrefix decodes the prefix of an index key and returns the // index id and a slice for the rest of the key. // // Don't use this function in the scan "hot path". func DecodeIndexKeyPrefix(a *DatumAlloc, desc *TableDescriptor, key []byte) ( indexID IndexID, remaining []byte, err error, ) { // TODO(dan): This whole operation is n^2 because of the interleaves // bookkeeping. We could improve it to n with a prefix tree of components. interleaves := append([]IndexDescriptor{desc.PrimaryIndex}, desc.Indexes...) for component := 0; ; component++ { var tableID ID key, tableID, indexID, err = DecodeTableIDIndexID(key) if err != nil { return 0, nil, err } if tableID == desc.ID { // Once desc's table id has been decoded, there can be no more // interleaves. remaining = key break } for i := len(interleaves) - 1; i >= 0; i-- { if len(interleaves[i].Interleave.Ancestors) <= component || interleaves[i].Interleave.Ancestors[component].TableID != tableID || interleaves[i].Interleave.Ancestors[component].IndexID != indexID { // This component, and thus this interleave, doesn't match what was // decoded, remove it. copy(interleaves[i:], interleaves[i+1:]) interleaves = interleaves[:len(interleaves)-1] } } // The decoded key doesn't many any known interleaves if len(interleaves) == 0 { return 0, nil, errors.Errorf("no known interleaves for key") } // Anything left has the same SharedPrefixLen at index `component`, so just // use the first one. for i := uint32(0); i < interleaves[0].Interleave.Ancestors[component].SharedPrefixLen; i++ { l, err := encoding.PeekLength(key) if err != nil { return 0, nil, err } key = key[l:] } // We reuse NotNullDescending as the interleave sentinel, consume it. var ok bool key, ok = encoding.DecodeIfNotNull(key) if !ok { return 0, nil, errors.Errorf("invalid interleave key") } } return indexID, key, err }
// prettyKey pretty-prints the specified key, skipping over the first skip // fields. func prettyKey(key roachpb.Key, skip int) string { if !bytes.HasPrefix(key, keys.TableDataPrefix) { return fmt.Sprintf("index key missing table data prefix: %q vs %q", key, keys.TableDataPrefix) } key = key[len(keys.TableDataPrefix):] var buf bytes.Buffer for k := 0; len(key) > 0; k++ { var d interface{} var err error switch encoding.PeekType(key) { case encoding.Null: key, _ = encoding.DecodeIfNull(key) d = parser.DNull case encoding.NotNull: key, _ = encoding.DecodeIfNotNull(key) d = "#" case encoding.Int: var i int64 key, i, err = encoding.DecodeVarint(key) d = parser.DInt(i) case encoding.Float: var f float64 key, f, err = encoding.DecodeFloat(key, nil) d = parser.DFloat(f) case encoding.Bytes: var s string key, s, err = encoding.DecodeString(key, nil) d = parser.DString(s) case encoding.Time: var t time.Time key, t, err = encoding.DecodeTime(key) d = parser.DTimestamp{Time: t} default: // This shouldn't ever happen, but if it does let the loop exit. key = nil d = "unknown" } if skip > 0 { skip-- continue } if err != nil { fmt.Fprintf(&buf, "/<%v>", err) continue } fmt.Fprintf(&buf, "/%s", d) } return buf.String() }